Compare commits

...

20 Commits

Author SHA1 Message Date
David Tolnay fccb9499bc Release 1.0.163 2023-05-10 00:47:53 -07:00
David Tolnay a139ab2572 Adjust PR 2446 with less overgeneralized name 2023-05-10 00:45:52 -07:00
David Tolnay 1d910a484c Format with rustfmt 1.5.2-nightly 2023-05-10 00:40:39 -07:00
David Tolnay ee9166ec97 Revise comments on the FlatMapDeserializer entry taker 2023-05-10 00:39:10 -07:00
David Tolnay b5a9eff32e Resolve while_let_on_iterator clippy lint
warning: this loop could be written as a `for` loop
        --> serde/src/private/de.rs:2905:9
         |
    2905 |         while let Some(item) = self.iter.next() {
         |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for item in self.iter.by_ref()`
         |
         = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
         = note: `#[warn(clippy::while_let_on_iterator)]` on by default
2023-05-10 00:23:38 -07:00
David Tolnay 9441a29663 Merge pull request #2446 from Mingun/dedup2
Eliminate some duplicated code
2023-05-10 00:13:44 -07:00
Mingun ab6588ef74 Extract duplicated code into a function 2023-05-08 10:39:30 +05:00
Mingun 1d11f03449 Extract logic of taking flattened fields into a function 2023-05-08 10:39:27 +05:00
Mingun e11d01fe1d Remove constructors for FlatMapAccess and FlatStructAccess
They are used only in one place each, so for simplifying understanding it is better to inline them
2023-05-08 09:40:06 +05:00
Mingun a901f50850 FlatMapAccess and FlatStructAccess does not need to be public 2023-05-08 09:37:15 +05:00
Mingun c399e9c368 Remove FlatInternallyTaggedAccess because it is the same as FlatMapAccess 2023-05-08 09:25:18 +05:00
David Tolnay 25381be0c9 Merge pull request #2442 from taiki-e/derive-build-script
Remove build script from serde_derive
2023-05-05 14:35:09 -07:00
Taiki Endo ef2a7c753f Remove build script from serde_derive
The current serde_derive's MSRV is 1.56, and both underscore consts and
ptr::addr_of! are always available.
2023-05-06 05:34:38 +09:00
David Tolnay 99f165b45a Release 1.0.162 2023-05-04 18:46:55 -07:00
David Tolnay 2fb5560746 Attempt to generate just one copy of TagContentOtherFieldVisitor's field matching 2023-05-04 18:42:21 -07:00
David Tolnay bd653ab30c Format PR 2377 with rustfmt 2023-05-04 18:42:21 -07:00
David Tolnay b5d68aedaa Merge pull request #2377 from mfro/master
Allow bytes for adjacently tagged enums
2023-05-04 18:39:57 -07:00
David Tolnay 624879c4c6 Merge pull request #2441 from dtolnay/test
Reimplement tests that touched serde_test internal API
2023-05-04 17:42:07 -07:00
David Tolnay bd9e9abf35 Reimplement tests that touched serde_test internal API 2023-05-04 17:38:58 -07:00
Max Froehlich a803ec1c1f Allow bytes for adjantly tagged enums 2023-02-18 12:49:23 -08:00
16 changed files with 175 additions and 263 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde" name = "serde"
version = "1.0.161" # remember to update html_root_url and serde_derive dependency version = "1.0.163" # remember to update html_root_url and serde_derive dependency
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs" build = "build.rs"
categories = ["encoding", "no-std"] categories = ["encoding", "no-std"]
@@ -15,7 +15,7 @@ repository = "https://github.com/serde-rs/serde"
rust-version = "1.19" rust-version = "1.19"
[dependencies] [dependencies]
serde_derive = { version = "=1.0.161", optional = true, path = "../serde_derive" } serde_derive = { version = "=1.0.163", optional = true, path = "../serde_derive" }
[dev-dependencies] [dev-dependencies]
serde_derive = { version = "1.0", path = "../serde_derive" } serde_derive = { version = "1.0", path = "../serde_derive" }
+5 -6
View File
@@ -994,7 +994,8 @@ seq_impl!(
HashSet::clear, HashSet::clear,
HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()), HashSet::with_capacity_and_hasher(size_hint::cautious(seq.size_hint()), S::default()),
HashSet::reserve, HashSet::reserve,
HashSet::insert); HashSet::insert
);
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
seq_impl!( seq_impl!(
@@ -1409,16 +1410,14 @@ macro_rules! map_impl {
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
map_impl!( map_impl!(BTreeMap<K: Ord, V>, map, BTreeMap::new());
BTreeMap<K: Ord, V>,
map,
BTreeMap::new());
#[cfg(feature = "std")] #[cfg(feature = "std")]
map_impl!( map_impl!(
HashMap<K: Eq + Hash, V, S: BuildHasher + Default>, HashMap<K: Eq + Hash, V, S: BuildHasher + Default>,
map, map,
HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default())); HashMap::with_capacity_and_hasher(size_hint::cautious(map.size_hint()), S::default())
);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -93,7 +93,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Serde types in rustdoc of other crates get linked to here. // Serde types in rustdoc of other crates get linked to here.
#![doc(html_root_url = "https://docs.rs/serde/1.0.161")] #![doc(html_root_url = "https://docs.rs/serde/1.0.163")]
// Support using Serde without the standard library! // Support using Serde without the standard library!
#![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), no_std)]
// Unstable functionality only if the user asks for it. For tracking and // Unstable functionality only if the user asks for it. For tracking and
+48 -98
View File
@@ -982,9 +982,16 @@ mod content {
where where
E: de::Error, E: de::Error,
{ {
if field == self.tag { self.visit_bytes(field.as_bytes())
}
fn visit_bytes<E>(self, field: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
if field == self.tag.as_bytes() {
Ok(TagContentOtherField::Tag) Ok(TagContentOtherField::Tag)
} else if field == self.content { } else if field == self.content.as_bytes() {
Ok(TagContentOtherField::Content) Ok(TagContentOtherField::Content)
} else { } else {
Ok(TagContentOtherField::Other) Ok(TagContentOtherField::Other)
@@ -2731,11 +2738,7 @@ where
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
visitor.visit_map(FlatInternallyTaggedAccess { self.deserialize_map(visitor)
iter: self.0.iter_mut(),
pending: None,
_marker: PhantomData,
})
} }
fn deserialize_enum<V>( fn deserialize_enum<V>(
@@ -2747,17 +2750,8 @@ where
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
for item in self.0.iter_mut() { for entry in self.0.iter_mut() {
// items in the vector are nulled out when used. So we can only use if let Some((key, value)) = flat_map_take_entry(entry, variants) {
// an item if it's still filled in and if the field is one we care
// about.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |x| variants.contains(&x)),
};
if use_item {
let (key, value) = item.take().unwrap();
return visitor.visit_enum(EnumDeserializer::new(key, Some(value))); return visitor.visit_enum(EnumDeserializer::new(key, Some(value)));
} }
} }
@@ -2772,7 +2766,11 @@ where
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
visitor.visit_map(FlatMapAccess::new(self.0.iter())) visitor.visit_map(FlatMapAccess {
iter: self.0.iter(),
pending_content: None,
_marker: PhantomData,
})
} }
fn deserialize_struct<V>( fn deserialize_struct<V>(
@@ -2784,7 +2782,12 @@ where
where where
V: Visitor<'de>, V: Visitor<'de>,
{ {
visitor.visit_map(FlatStructAccess::new(self.0.iter_mut(), fields)) visitor.visit_map(FlatStructAccess {
iter: self.0.iter_mut(),
pending_content: None,
fields: fields,
_marker: PhantomData,
})
} }
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error> fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
@@ -2838,25 +2841,12 @@ where
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatMapAccess<'a, 'de: 'a, E> { struct FlatMapAccess<'a, 'de: 'a, E> {
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>, iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<&'a Content<'de>>, pending_content: Option<&'a Content<'de>>,
_marker: PhantomData<E>, _marker: PhantomData<E>,
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatMapAccess<'a, 'de, E> {
fn new(
iter: slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
) -> FlatMapAccess<'a, 'de, E> {
FlatMapAccess {
iter: iter,
pending_content: None,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E> impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
where where
@@ -2871,6 +2861,10 @@ where
for item in &mut self.iter { for item in &mut self.iter {
// Items in the vector are nulled out when used by a struct. // Items in the vector are nulled out when used by a struct.
if let Some((ref key, ref content)) = *item { if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending_content = Some(content); self.pending_content = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some); return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
} }
@@ -2890,28 +2884,13 @@ where
} }
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatStructAccess<'a, 'de: 'a, E> { struct FlatStructAccess<'a, 'de: 'a, E> {
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
pending_content: Option<Content<'de>>, pending_content: Option<Content<'de>>,
fields: &'static [&'static str], fields: &'static [&'static str],
_marker: PhantomData<E>, _marker: PhantomData<E>,
} }
#[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> FlatStructAccess<'a, 'de, E> {
fn new(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
fields: &'static [&'static str],
) -> FlatStructAccess<'a, 'de, E> {
FlatStructAccess {
iter: iter,
pending_content: None,
fields: fields,
_marker: PhantomData,
}
}
}
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E> impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
where where
@@ -2923,17 +2902,8 @@ where
where where
T: DeserializeSeed<'de>, T: DeserializeSeed<'de>,
{ {
while let Some(item) = self.iter.next() { for entry in self.iter.by_ref() {
// items in the vector are nulled out when used. So we can only use if let Some((key, content)) = flat_map_take_entry(entry, self.fields) {
// an item if it's still filled in and if the field is one we care
// about. In case we do not know which fields we want, we take them all.
let use_item = match *item {
None => false,
Some((ref c, _)) => c.as_str().map_or(false, |key| self.fields.contains(&key)),
};
if use_item {
let (key, content) = item.take().unwrap();
self.pending_content = Some(content); self.pending_content = Some(content);
return seed.deserialize(ContentDeserializer::new(key)).map(Some); return seed.deserialize(ContentDeserializer::new(key)).map(Some);
} }
@@ -2952,44 +2922,24 @@ where
} }
} }
/// Claims one key-value pair from a FlatMapDeserializer's field buffer if the
/// field name matches any of the recognized ones.
#[cfg(any(feature = "std", feature = "alloc"))] #[cfg(any(feature = "std", feature = "alloc"))]
pub struct FlatInternallyTaggedAccess<'a, 'de: 'a, E> { fn flat_map_take_entry<'de>(
iter: slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>, entry: &mut Option<(Content<'de>, Content<'de>)>,
pending: Option<&'a Content<'de>>, recognized: &[&str],
_marker: PhantomData<E>, ) -> Option<(Content<'de>, Content<'de>)> {
} // Entries in the FlatMapDeserializer buffer are nulled out as they get
// claimed for deserialization. We only use an entry if it is still present
// and if the field is one recognized by the current data structure.
let is_recognized = match entry {
None => false,
Some((k, _v)) => k.as_str().map_or(false, |name| recognized.contains(&name)),
};
#[cfg(any(feature = "std", feature = "alloc"))] if is_recognized {
impl<'a, 'de, E> MapAccess<'de> for FlatInternallyTaggedAccess<'a, 'de, E> entry.take()
where } else {
E: Error, None
{
type Error = E;
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
where
T: DeserializeSeed<'de>,
{
for item in &mut self.iter {
if let Some((ref key, ref content)) = *item {
// Do not take(), instead borrow this entry. The internally tagged
// enum does its own buffering so we can't tell whether this entry
// is going to be consumed. Borrowing here leaves the entry
// available for later flattened fields.
self.pending = Some(content);
return seed.deserialize(ContentRefDeserializer::new(key)).map(Some);
}
}
Ok(None)
}
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
where
T: DeserializeSeed<'de>,
{
match self.pending.take() {
Some(value) => seed.deserialize(ContentRefDeserializer::new(value)),
None => panic!("value is missing"),
}
} }
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_derive" name = "serde_derive"
version = "1.0.161" # remember to update html_root_url version = "1.0.163" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
categories = ["no-std"] categories = ["no-std"]
description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]"
-38
View File
@@ -1,38 +0,0 @@
use std::env;
use std::process::Command;
use std::str;
// The rustc-cfg strings below are *not* public API. Please let us know by
// opening a GitHub issue if your build environment requires some way to enable
// these cfgs other than by executing our build script.
fn main() {
println!("cargo:rerun-if-changed=build.rs");
let minor = match rustc_minor_version() {
Some(minor) => minor,
None => return,
};
// Underscore const names stabilized in Rust 1.37:
// https://blog.rust-lang.org/2019/08/15/Rust-1.37.0.html#using-unnamed-const-items-for-macros
if minor < 37 {
println!("cargo:rustc-cfg=no_underscore_consts");
}
// The ptr::addr_of! macro stabilized in Rust 1.51:
// https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
if minor < 51 {
println!("cargo:rustc-cfg=no_ptr_addr_of");
}
}
fn rustc_minor_version() -> Option<u32> {
let rustc = env::var_os("RUSTC")?;
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
if pieces.next() != Some("rustc 1") {
return None;
}
pieces.next()?.parse().ok()
}
+24 -31
View File
@@ -69,8 +69,6 @@ pub fn expand_derive_deserialize(
Ok(dummy::wrap_in_const( Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(), cont.attrs.custom_serde_path(),
"DESERIALIZE",
ident,
impl_block, impl_block,
)) ))
} }
@@ -3086,23 +3084,31 @@ struct DeTypeGenerics<'a>(&'a Parameters);
#[cfg(feature = "deserialize_in_place")] #[cfg(feature = "deserialize_in_place")]
struct InPlaceTypeGenerics<'a>(&'a Parameters); struct InPlaceTypeGenerics<'a>(&'a Parameters);
fn de_type_generics_to_tokens(
mut generics: syn::Generics,
borrowed: &BorrowedLifetimes,
tokens: &mut TokenStream,
) {
if borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
// Prepend 'de lifetime to list of generics
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
}
impl<'a> ToTokens for DeTypeGenerics<'a> { impl<'a> ToTokens for DeTypeGenerics<'a> {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let mut generics = self.0.generics.clone(); de_type_generics_to_tokens(self.0.generics.clone(), &self.0.borrowed, tokens);
if self.0.borrowed.de_lifetime_param().is_some() {
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
} }
} }
@@ -3115,20 +3121,7 @@ impl<'a> ToTokens for InPlaceTypeGenerics<'a> {
.chain(generics.params) .chain(generics.params)
.collect(); .collect();
if self.0.borrowed.de_lifetime_param().is_some() { de_type_generics_to_tokens(generics, &self.0.borrowed, tokens);
let def = syn::LifetimeParam {
attrs: Vec::new(),
lifetime: syn::Lifetime::new("'de", Span::call_site()),
colon_token: None,
bounds: Punctuated::new(),
};
generics.params = Some(syn::GenericParam::Lifetime(def))
.into_iter()
.chain(generics.params)
.collect();
}
let (_, ty_generics, _) = generics.split_for_impl();
ty_generics.to_tokens(tokens);
} }
} }
+3 -19
View File
@@ -1,23 +1,11 @@
use proc_macro2::{Ident, TokenStream}; use proc_macro2::TokenStream;
use quote::format_ident;
use syn; use syn;
use try; use try;
pub fn wrap_in_const( pub fn wrap_in_const(serde_path: Option<&syn::Path>, code: TokenStream) -> TokenStream {
serde_path: Option<&syn::Path>,
trait_: &str,
ty: &Ident,
code: TokenStream,
) -> TokenStream {
let try_replacement = try::replacement(); let try_replacement = try::replacement();
let dummy_const = if cfg!(no_underscore_consts) {
format_ident!("_IMPL_{}_FOR_{}", trait_, unraw(ty))
} else {
format_ident!("_")
};
let use_serde = match serde_path { let use_serde = match serde_path {
Some(path) => quote! { Some(path) => quote! {
use #path as _serde; use #path as _serde;
@@ -31,14 +19,10 @@ pub fn wrap_in_const(
quote! { quote! {
#[doc(hidden)] #[doc(hidden)]
#[allow(non_upper_case_globals, unused_attributes, unused_qualifications)] #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
const #dummy_const: () = { const _: () = {
#use_serde #use_serde
#try_replacement #try_replacement
#code #code
}; };
} }
} }
fn unraw(ident: &Ident) -> String {
ident.to_string().trim_start_matches("r#").to_owned()
}
+1 -1
View File
@@ -13,7 +13,7 @@
//! //!
//! [https://serde.rs/derive.html]: https://serde.rs/derive.html //! [https://serde.rs/derive.html]: https://serde.rs/derive.html
#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.161")] #![doc(html_root_url = "https://docs.rs/serde_derive/1.0.163")]
#![allow(unknown_lints, bare_trait_objects)] #![allow(unknown_lints, bare_trait_objects)]
// Ignored clippy lints // Ignored clippy lints
#![allow( #![allow(
+7 -22
View File
@@ -97,29 +97,14 @@ fn pretend_fields_used_struct_packed(cont: &Container, fields: &[Field]) -> Toke
let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>(); let members = fields.iter().map(|field| &field.member).collect::<Vec<_>>();
#[cfg(not(no_ptr_addr_of))] quote! {
{ match _serde::__private::None::<&#type_ident #ty_generics> {
quote! { _serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => {
match _serde::__private::None::<&#type_ident #ty_generics> { #(
_serde::__private::Some(__v @ #type_ident { #(#members: _),* }) => { let _ = _serde::__private::ptr::addr_of!(__v.#members);
#( )*
let _ = _serde::__private::ptr::addr_of!(__v.#members);
)*
}
_ => {}
}
}
}
#[cfg(no_ptr_addr_of)]
{
let placeholders = (0usize..).map(|i| format_ident!("__v{}", i));
quote! {
match _serde::__private::None::<#type_ident #ty_generics> {
_serde::__private::Some(#type_ident { #(#members: #placeholders),* }) => {}
_ => {}
} }
_ => {}
} }
} }
} }
-2
View File
@@ -59,8 +59,6 @@ pub fn expand_derive_serialize(
Ok(dummy::wrap_in_const( Ok(dummy::wrap_in_const(
cont.attrs.custom_serde_path(), cont.attrs.custom_serde_path(),
"SERIALIZE",
ident,
impl_block, impl_block,
)) ))
} }
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "serde_test" name = "serde_test"
version = "1.0.161" # remember to update html_root_url version = "1.0.163" # remember to update html_root_url
authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"] authors = ["Erick Tryzelaar <erick.tryzelaar@gmail.com>", "David Tolnay <dtolnay@gmail.com>"]
build = "build.rs" build = "build.rs"
categories = ["development-tools::testing"] categories = ["development-tools::testing"]
+1 -5
View File
@@ -140,7 +140,7 @@
//! # } //! # }
//! ``` //! ```
#![doc(html_root_url = "https://docs.rs/serde_test/1.0.161")] #![doc(html_root_url = "https://docs.rs/serde_test/1.0.163")]
#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] #![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))]
// Ignored clippy lints // Ignored clippy lints
#![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))] #![cfg_attr(feature = "cargo-clippy", allow(float_cmp, needless_doctest_main))]
@@ -182,7 +182,3 @@ pub use assert::{
pub use token::Token; pub use token::Token;
pub use configure::{Compact, Configure, Readable}; pub use configure::{Compact, Configure, Readable};
// Not public API.
#[doc(hidden)]
pub use de::Deserializer;
+47
View File
@@ -2317,6 +2317,53 @@ fn test_internally_tagged_enum_new_type_with_unit() {
); );
} }
#[test]
fn test_adjacently_tagged_enum_bytes() {
#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[serde(tag = "t", content = "c")]
enum Data {
A { a: i32 },
}
let data = Data::A { a: 0 };
assert_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Str("t"),
Token::Str("A"),
Token::Str("c"),
Token::Struct { name: "A", len: 1 },
Token::Str("a"),
Token::I32(0),
Token::StructEnd,
Token::StructEnd,
],
);
assert_de_tokens(
&data,
&[
Token::Struct {
name: "Data",
len: 2,
},
Token::Bytes(b"t"),
Token::Str("A"),
Token::Bytes(b"c"),
Token::Struct { name: "A", len: 1 },
Token::Str("a"),
Token::I32(0),
Token::StructEnd,
Token::StructEnd,
],
);
}
#[test] #[test]
fn test_adjacently_tagged_enum_containing_flatten() { fn test_adjacently_tagged_enum_containing_flatten() {
#[derive(Serialize, Deserialize, PartialEq, Debug)] #[derive(Serialize, Deserialize, PartialEq, Debug)]
+17 -13
View File
@@ -4,6 +4,8 @@
clippy::used_underscore_binding clippy::used_underscore_binding
)] )]
use serde::de::value::{BorrowedStrDeserializer, MapDeserializer};
use serde::de::IntoDeserializer;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, assert_de_tokens_error, Token}; use serde_test::{assert_de_tokens, assert_de_tokens_error, Token};
@@ -130,20 +132,22 @@ fn test_cow() {
borrowed: Cow<'b, str>, borrowed: Cow<'b, str>,
} }
let tokens = &[ struct BorrowedStr(&'static str);
Token::Struct {
name: "Cows",
len: 2,
},
Token::Str("copied"),
Token::BorrowedStr("copied"),
Token::Str("borrowed"),
Token::BorrowedStr("borrowed"),
Token::StructEnd,
];
let mut de = serde_test::Deserializer::new(tokens); impl<'de> IntoDeserializer<'de> for BorrowedStr {
let cows = Cows::deserialize(&mut de).unwrap(); type Deserializer = BorrowedStrDeserializer<'de, serde::de::value::Error>;
fn into_deserializer(self) -> Self::Deserializer {
BorrowedStrDeserializer::new(self.0)
}
}
let de = MapDeserializer::new(IntoIterator::into_iter([
("copied", BorrowedStr("copied")),
("borrowed", BorrowedStr("borrowed")),
]));
let cows = Cows::deserialize(de).unwrap();
match cows.copied { match cows.copied {
Cow::Owned(ref s) if s == "copied" => {} Cow::Owned(ref s) if s == "copied" => {}
+17 -23
View File
@@ -33,7 +33,7 @@ use std::time::{Duration, UNIX_EPOCH};
use std::sync::atomic::{AtomicI64, AtomicU64}; use std::sync::atomic::{AtomicI64, AtomicU64};
use fnv::FnvHasher; use fnv::FnvHasher;
use serde::de::DeserializeOwned; use serde::de::{DeserializeOwned, IntoDeserializer};
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer};
use serde_test::{assert_de_tokens, Configure, Token}; use serde_test::{assert_de_tokens, Configure, Token};
@@ -202,9 +202,8 @@ fn assert_de_tokens_ignore(ignorable_tokens: &[Token]) {
.chain(vec![Token::MapEnd].into_iter()) .chain(vec![Token::MapEnd].into_iter())
.collect(); .collect();
let mut de = serde_test::Deserializer::new(&concated_tokens); let expected = IgnoreBase { a: 1 };
let base = IgnoreBase::deserialize(&mut de).unwrap(); assert_de_tokens(&expected, &concated_tokens);
assert_eq!(base, IgnoreBase { a: 1 });
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@@ -2245,39 +2244,34 @@ fn test_cstr() {
#[test] #[test]
fn test_atomics() { fn test_atomics() {
fn test<L, A, T>(load: L, val: T, token: Token) fn test<L, A, T>(load: L, val: T)
where where
L: Fn(&A, Ordering) -> T, L: Fn(&A, Ordering) -> T,
A: DeserializeOwned, A: DeserializeOwned,
T: PartialEq + Debug, T: PartialEq + Debug + Copy + for<'de> IntoDeserializer<'de>,
{ {
let tokens = &[token]; match A::deserialize(val.into_deserializer()) {
let mut de = serde_test::Deserializer::new(tokens);
match A::deserialize(&mut de) {
Ok(v) => { Ok(v) => {
let loaded = load(&v, Ordering::Relaxed); let loaded = load(&v, Ordering::Relaxed);
assert_eq!(val, loaded); assert_eq!(val, loaded);
} }
Err(e) => panic!("tokens failed to deserialize: {}", e), Err(e) => panic!("tokens failed to deserialize: {}", e),
};
if de.remaining() > 0 {
panic!("{} remaining tokens", de.remaining());
} }
} }
test(AtomicBool::load, true, Token::Bool(true)); test(AtomicBool::load, true);
test(AtomicI8::load, -127, Token::I8(-127i8)); test(AtomicI8::load, -127i8);
test(AtomicI16::load, -510, Token::I16(-510i16)); test(AtomicI16::load, -510i16);
test(AtomicI32::load, -131072, Token::I32(-131072i32)); test(AtomicI32::load, -131072i32);
test(AtomicIsize::load, -131072isize, Token::I32(-131072)); test(AtomicIsize::load, -131072isize);
test(AtomicU8::load, 127, Token::U8(127u8)); test(AtomicU8::load, 127u8);
test(AtomicU16::load, 510u16, Token::U16(510u16)); test(AtomicU16::load, 510u16);
test(AtomicU32::load, 131072u32, Token::U32(131072u32)); test(AtomicU32::load, 131072u32);
test(AtomicUsize::load, 131072usize, Token::U32(131072)); test(AtomicUsize::load, 131072usize);
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
{ {
test(AtomicI64::load, -8589934592, Token::I64(-8589934592)); test(AtomicI64::load, -8589934592i64);
test(AtomicU64::load, 8589934592u64, Token::U64(8589934592)); test(AtomicU64::load, 8589934592u64);
} }
} }