serde_derive_internals-0.26.0/.cargo_vcs_info.json0000644000000001120000000000000156310ustar { "git": { "sha1": "7aa4950504e64dc3987f0c69718d97b4b106d650" } } serde_derive_internals-0.26.0/Cargo.toml0000644000000024510000000000000136370ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "serde_derive_internals" version = "0.26.0" authors = ["Erick Tryzelaar ", "David Tolnay "] include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"] description = "AST representation used by Serde derive macros. Unstable." homepage = "https://serde.rs" documentation = "https://docs.rs/serde_derive_internals" keywords = ["serde", "serialization"] license = "MIT OR Apache-2.0" repository = "https://github.com/serde-rs/serde" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] [lib] path = "lib.rs" [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.syn] version = "1.0.60" features = ["derive", "parsing", "printing", "clone-impls"] default-features = false serde_derive_internals-0.26.0/Cargo.toml.orig000064400000000000000000000014310000000000000172730ustar 00000000000000[package] name = "serde_derive_internals" version = "0.26.0" # remember to update html_root_url authors = ["Erick Tryzelaar ", "David Tolnay "] license = "MIT OR Apache-2.0" description = "AST representation used by Serde derive macros. Unstable." homepage = "https://serde.rs" repository = "https://github.com/serde-rs/serde" documentation = "https://docs.rs/serde_derive_internals" keywords = ["serde", "serialization"] include = ["lib.rs", "src/**/*.rs", "LICENSE-APACHE", "LICENSE-MIT"] [lib] path = "lib.rs" [dependencies] proc-macro2 = "1.0" quote = "1.0" syn = { version = "1.0.60", default-features = false, features = ["derive", "parsing", "printing", "clone-impls"] } [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] serde_derive_internals-0.26.0/LICENSE-APACHE000064400000000000000000000251370000000000000163410ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. serde_derive_internals-0.26.0/LICENSE-MIT000064400000000000000000000017770000000000000160550ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. serde_derive_internals-0.26.0/lib.rs000064400000000000000000000026660000000000000155330ustar 00000000000000#![doc(html_root_url = "https://docs.rs/serde_derive_internals/0.26.0")] #![allow(unknown_lints, bare_trait_objects)] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints #![allow( clippy::cognitive_complexity, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6797 clippy::manual_map, clippy::missing_panics_doc, clippy::redundant_field_names, clippy::result_unit_err, clippy::should_implement_trait, clippy::trivially_copy_pass_by_ref, clippy::wildcard_in_or_patterns, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/5704 clippy::unnested_or_patterns, )] // Ignored clippy_pedantic lints #![allow( clippy::doc_markdown, clippy::enum_glob_use, clippy::items_after_statements, clippy::let_underscore_drop, clippy::match_same_arms, // clippy bug: https://github.com/rust-lang/rust-clippy/issues/6984 clippy::match_wildcard_for_single_variants, clippy::missing_errors_doc, clippy::module_name_repetitions, clippy::must_use_candidate, clippy::similar_names, clippy::struct_excessive_bools, clippy::too_many_lines, clippy::unused_self, clippy::wildcard_imports )] #[macro_use] extern crate syn; extern crate proc_macro2; extern crate quote; #[cfg_attr(serde_build_from_git, path = "../serde_derive/src/internals/mod.rs")] #[cfg_attr(not(serde_build_from_git), path = "src/mod.rs")] mod internals; pub use internals::*; serde_derive_internals-0.26.0/src/ast.rs000064400000000000000000000135000000000000000163300ustar 00000000000000//! A Serde ast, parsed from the Syn ast and ready to generate Rust code. use internals::attr; use internals::check; use internals::{Ctxt, Derive}; use syn; use syn::punctuated::Punctuated; /// A source data structure annotated with `#[derive(Serialize)]` and/or `#[derive(Deserialize)]`, /// parsed into an internal representation. pub struct Container<'a> { /// The struct or enum name (without generics). pub ident: syn::Ident, /// Attributes on the structure, parsed for Serde. pub attrs: attr::Container, /// The contents of the struct or enum. pub data: Data<'a>, /// Any generics on the struct or enum. pub generics: &'a syn::Generics, /// Original input. pub original: &'a syn::DeriveInput, } /// The fields of a struct or enum. /// /// Analagous to `syn::Data`. pub enum Data<'a> { Enum(Vec>), Struct(Style, Vec>), } /// A variant of an enum. pub struct Variant<'a> { pub ident: syn::Ident, pub attrs: attr::Variant, pub style: Style, pub fields: Vec>, pub original: &'a syn::Variant, } /// A field of a struct. pub struct Field<'a> { pub member: syn::Member, pub attrs: attr::Field, pub ty: &'a syn::Type, pub original: &'a syn::Field, } #[derive(Copy, Clone)] pub enum Style { /// Named fields. Struct, /// Many unnamed fields. Tuple, /// One unnamed field. Newtype, /// No fields. Unit, } impl<'a> Container<'a> { /// Convert the raw Syn ast into a parsed container object, collecting errors in `cx`. pub fn from_ast( cx: &Ctxt, item: &'a syn::DeriveInput, derive: Derive, ) -> Option> { let mut attrs = attr::Container::from_ast(cx, item); let mut data = match &item.data { syn::Data::Enum(data) => Data::Enum(enum_from_ast(cx, &data.variants, attrs.default())), syn::Data::Struct(data) => { let (style, fields) = struct_from_ast(cx, &data.fields, None, attrs.default()); Data::Struct(style, fields) } syn::Data::Union(_) => { cx.error_spanned_by(item, "Serde does not support derive for unions"); return None; } }; let mut has_flatten = false; match &mut data { Data::Enum(variants) => { for variant in variants { variant.attrs.rename_by_rules(attrs.rename_all_rules()); for field in &mut variant.fields { if field.attrs.flatten() { has_flatten = true; } field .attrs .rename_by_rules(variant.attrs.rename_all_rules()); } } } Data::Struct(_, fields) => { for field in fields { if field.attrs.flatten() { has_flatten = true; } field.attrs.rename_by_rules(attrs.rename_all_rules()); } } } if has_flatten { attrs.mark_has_flatten(); } let mut item = Container { ident: item.ident.clone(), attrs, data, generics: &item.generics, original: item, }; check::check(cx, &mut item, derive); Some(item) } } impl<'a> Data<'a> { pub fn all_fields(&'a self) -> Box> + 'a> { match self { Data::Enum(variants) => { Box::new(variants.iter().flat_map(|variant| variant.fields.iter())) } Data::Struct(_, fields) => Box::new(fields.iter()), } } pub fn has_getter(&self) -> bool { self.all_fields().any(|f| f.attrs.getter().is_some()) } } fn enum_from_ast<'a>( cx: &Ctxt, variants: &'a Punctuated, container_default: &attr::Default, ) -> Vec> { variants .iter() .map(|variant| { let attrs = attr::Variant::from_ast(cx, variant); let (style, fields) = struct_from_ast(cx, &variant.fields, Some(&attrs), container_default); Variant { ident: variant.ident.clone(), attrs, style, fields, original: variant, } }) .collect() } fn struct_from_ast<'a>( cx: &Ctxt, fields: &'a syn::Fields, attrs: Option<&attr::Variant>, container_default: &attr::Default, ) -> (Style, Vec>) { match fields { syn::Fields::Named(fields) => ( Style::Struct, fields_from_ast(cx, &fields.named, attrs, container_default), ), syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => ( Style::Newtype, fields_from_ast(cx, &fields.unnamed, attrs, container_default), ), syn::Fields::Unnamed(fields) => ( Style::Tuple, fields_from_ast(cx, &fields.unnamed, attrs, container_default), ), syn::Fields::Unit => (Style::Unit, Vec::new()), } } fn fields_from_ast<'a>( cx: &Ctxt, fields: &'a Punctuated, attrs: Option<&attr::Variant>, container_default: &attr::Default, ) -> Vec> { fields .iter() .enumerate() .map(|(i, field)| Field { member: match &field.ident { Some(ident) => syn::Member::Named(ident.clone()), None => syn::Member::Unnamed(i.into()), }, attrs: attr::Field::from_ast(cx, i, field, attrs, container_default), ty: &field.ty, original: field, }) .collect() } serde_derive_internals-0.26.0/src/attr.rs000064400000000000000000002076430000000000000165300ustar 00000000000000use internals::respan::respan; use internals::symbol::*; use internals::{ungroup, Ctxt}; use proc_macro2::{Spacing, Span, TokenStream, TokenTree}; use quote::ToTokens; use std::borrow::Cow; use std::collections::BTreeSet; use syn; use syn::parse::{self, Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::Ident; use syn::Meta::{List, NameValue, Path}; use syn::NestedMeta::{Lit, Meta}; // This module handles parsing of `#[serde(...)]` attributes. The entrypoints // are `attr::Container::from_ast`, `attr::Variant::from_ast`, and // `attr::Field::from_ast`. Each returns an instance of the corresponding // struct. Note that none of them return a Result. Unrecognized, malformed, or // duplicated attributes result in a span_err but otherwise are ignored. The // user will see errors simultaneously for all bad attributes in the crate // rather than just the first. pub use internals::case::RenameRule; struct Attr<'c, T> { cx: &'c Ctxt, name: Symbol, tokens: TokenStream, value: Option, } impl<'c, T> Attr<'c, T> { fn none(cx: &'c Ctxt, name: Symbol) -> Self { Attr { cx, name, tokens: TokenStream::new(), value: None, } } fn set(&mut self, obj: A, value: T) { let tokens = obj.into_token_stream(); if self.value.is_some() { self.cx .error_spanned_by(tokens, format!("duplicate serde attribute `{}`", self.name)); } else { self.tokens = tokens; self.value = Some(value); } } fn set_opt(&mut self, obj: A, value: Option) { if let Some(value) = value { self.set(obj, value); } } fn set_if_none(&mut self, value: T) { if self.value.is_none() { self.value = Some(value); } } fn get(self) -> Option { self.value } fn get_with_tokens(self) -> Option<(TokenStream, T)> { match self.value { Some(v) => Some((self.tokens, v)), None => None, } } } struct BoolAttr<'c>(Attr<'c, ()>); impl<'c> BoolAttr<'c> { fn none(cx: &'c Ctxt, name: Symbol) -> Self { BoolAttr(Attr::none(cx, name)) } fn set_true(&mut self, obj: A) { self.0.set(obj, ()); } fn get(&self) -> bool { self.0.value.is_some() } } struct VecAttr<'c, T> { cx: &'c Ctxt, name: Symbol, first_dup_tokens: TokenStream, values: Vec, } impl<'c, T> VecAttr<'c, T> { fn none(cx: &'c Ctxt, name: Symbol) -> Self { VecAttr { cx, name, first_dup_tokens: TokenStream::new(), values: Vec::new(), } } fn insert(&mut self, obj: A, value: T) { if self.values.len() == 1 { self.first_dup_tokens = obj.into_token_stream(); } self.values.push(value); } fn at_most_one(mut self) -> Result, ()> { if self.values.len() > 1 { let dup_token = self.first_dup_tokens; self.cx.error_spanned_by( dup_token, format!("duplicate serde attribute `{}`", self.name), ); Err(()) } else { Ok(self.values.pop()) } } fn get(self) -> Vec { self.values } } pub struct Name { serialize: String, serialize_renamed: bool, deserialize: String, deserialize_renamed: bool, deserialize_aliases: Vec, } #[allow(deprecated)] fn unraw(ident: &Ident) -> String { // str::trim_start_matches was added in 1.30, trim_left_matches deprecated // in 1.33. We currently support rustc back to 1.15 so we need to continue // to use the deprecated one. ident.to_string().trim_left_matches("r#").to_owned() } impl Name { fn from_attrs( source_name: String, ser_name: Attr, de_name: Attr, de_aliases: Option>, ) -> Name { let deserialize_aliases = match de_aliases { Some(de_aliases) => { let mut alias_list = BTreeSet::new(); for alias_name in de_aliases.get() { alias_list.insert(alias_name); } alias_list.into_iter().collect() } None => Vec::new(), }; let ser_name = ser_name.get(); let ser_renamed = ser_name.is_some(); let de_name = de_name.get(); let de_renamed = de_name.is_some(); Name { serialize: ser_name.unwrap_or_else(|| source_name.clone()), serialize_renamed: ser_renamed, deserialize: de_name.unwrap_or(source_name), deserialize_renamed: de_renamed, deserialize_aliases, } } /// Return the container name for the container when serializing. pub fn serialize_name(&self) -> String { self.serialize.clone() } /// Return the container name for the container when deserializing. pub fn deserialize_name(&self) -> String { self.deserialize.clone() } fn deserialize_aliases(&self) -> Vec { let mut aliases = self.deserialize_aliases.clone(); let main_name = self.deserialize_name(); if !aliases.contains(&main_name) { aliases.push(main_name); } aliases } } pub struct RenameAllRules { serialize: RenameRule, deserialize: RenameRule, } /// Represents struct or enum attribute information. pub struct Container { name: Name, transparent: bool, deny_unknown_fields: bool, default: Default, rename_all_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, tag: TagType, type_from: Option, type_try_from: Option, type_into: Option, remote: Option, identifier: Identifier, has_flatten: bool, serde_path: Option, is_packed: bool, /// Error message generated when type can't be deserialized expecting: Option, } /// Styles of representing an enum. pub enum TagType { /// The default. /// /// ```json /// {"variant1": {"key1": "value1", "key2": "value2"}} /// ``` External, /// `#[serde(tag = "type")]` /// /// ```json /// {"type": "variant1", "key1": "value1", "key2": "value2"} /// ``` Internal { tag: String }, /// `#[serde(tag = "t", content = "c")]` /// /// ```json /// {"t": "variant1", "c": {"key1": "value1", "key2": "value2"}} /// ``` Adjacent { tag: String, content: String }, /// `#[serde(untagged)]` /// /// ```json /// {"key1": "value1", "key2": "value2"} /// ``` None, } /// Whether this enum represents the fields of a struct or the variants of an /// enum. #[derive(Copy, Clone)] pub enum Identifier { /// It does not. No, /// This enum represents the fields of a struct. All of the variants must be /// unit variants, except possibly one which is annotated with /// `#[serde(other)]` and is a newtype variant. Field, /// This enum represents the variants of an enum. All of the variants must /// be unit variants. Variant, } impl Identifier { #[cfg(feature = "deserialize_in_place")] pub fn is_some(self) -> bool { match self { Identifier::No => false, Identifier::Field | Identifier::Variant => true, } } } impl Container { /// Extract out the `#[serde(...)]` attributes from an item. pub fn from_ast(cx: &Ctxt, item: &syn::DeriveInput) -> Self { let mut ser_name = Attr::none(cx, RENAME); let mut de_name = Attr::none(cx, RENAME); let mut transparent = BoolAttr::none(cx, TRANSPARENT); let mut deny_unknown_fields = BoolAttr::none(cx, DENY_UNKNOWN_FIELDS); let mut default = Attr::none(cx, DEFAULT); let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL); let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL); let mut ser_bound = Attr::none(cx, BOUND); let mut de_bound = Attr::none(cx, BOUND); let mut untagged = BoolAttr::none(cx, UNTAGGED); let mut internal_tag = Attr::none(cx, TAG); let mut content = Attr::none(cx, CONTENT); let mut type_from = Attr::none(cx, FROM); let mut type_try_from = Attr::none(cx, TRY_FROM); let mut type_into = Attr::none(cx, INTO); let mut remote = Attr::none(cx, REMOTE); let mut field_identifier = BoolAttr::none(cx, FIELD_IDENTIFIER); let mut variant_identifier = BoolAttr::none(cx, VARIANT_IDENTIFIER); let mut serde_path = Attr::none(cx, CRATE); let mut expecting = Attr::none(cx, EXPECTING); for meta_item in item .attrs .iter() .flat_map(|attr| get_serde_meta_items(cx, attr)) .flatten() { match &meta_item { // Parse `#[serde(rename = "foo")]` Meta(NameValue(m)) if m.path == RENAME => { if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { ser_name.set(&m.path, s.value()); de_name.set(&m.path, s.value()); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` Meta(List(m)) if m.path == RENAME => { if let Ok((ser, de)) = get_renames(cx, &m.nested) { ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); de_name.set_opt(&m.path, de.map(syn::LitStr::value)); } } // Parse `#[serde(rename_all = "foo")]` Meta(NameValue(m)) if m.path == RENAME_ALL => { if let Ok(s) = get_lit_str(cx, RENAME_ALL, &m.lit) { match RenameRule::from_str(&s.value()) { Ok(rename_rule) => { rename_all_ser_rule.set(&m.path, rename_rule); rename_all_de_rule.set(&m.path, rename_rule); } Err(err) => cx.error_spanned_by(s, err), } } } // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` Meta(List(m)) if m.path == RENAME_ALL => { if let Ok((ser, de)) = get_renames(cx, &m.nested) { if let Some(ser) = ser { match RenameRule::from_str(&ser.value()) { Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule), Err(err) => cx.error_spanned_by(ser, err), } } if let Some(de) = de { match RenameRule::from_str(&de.value()) { Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule), Err(err) => cx.error_spanned_by(de, err), } } } } // Parse `#[serde(transparent)]` Meta(Path(word)) if word == TRANSPARENT => { transparent.set_true(word); } // Parse `#[serde(deny_unknown_fields)]` Meta(Path(word)) if word == DENY_UNKNOWN_FIELDS => { deny_unknown_fields.set_true(word); } // Parse `#[serde(default)]` Meta(Path(word)) if word == DEFAULT => match &item.data { syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { syn::Fields::Named(_) => { default.set(word, Default::Default); } syn::Fields::Unnamed(_) | syn::Fields::Unit => cx.error_spanned_by( fields, "#[serde(default)] can only be used on structs with named fields", ), }, syn::Data::Enum(syn::DataEnum { enum_token, .. }) => cx.error_spanned_by( enum_token, "#[serde(default)] can only be used on structs with named fields", ), syn::Data::Union(syn::DataUnion { union_token, .. }) => cx.error_spanned_by( union_token, "#[serde(default)] can only be used on structs with named fields", ), }, // Parse `#[serde(default = "...")]` Meta(NameValue(m)) if m.path == DEFAULT => { if let Ok(path) = parse_lit_into_expr_path(cx, DEFAULT, &m.lit) { match &item.data { syn::Data::Struct(syn::DataStruct { fields, .. }) => { match fields { syn::Fields::Named(_) => { default.set(&m.path, Default::Path(path)); } syn::Fields::Unnamed(_) | syn::Fields::Unit => cx .error_spanned_by( fields, "#[serde(default = \"...\")] can only be used on structs with named fields", ), } } syn::Data::Enum(syn::DataEnum { enum_token, .. }) => cx .error_spanned_by( enum_token, "#[serde(default = \"...\")] can only be used on structs with named fields", ), syn::Data::Union(syn::DataUnion { union_token, .. }) => cx.error_spanned_by( union_token, "#[serde(default = \"...\")] can only be used on structs with named fields", ), } } } // Parse `#[serde(bound = "T: SomeBound")]` Meta(NameValue(m)) if m.path == BOUND => { if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { ser_bound.set(&m.path, where_predicates.clone()); de_bound.set(&m.path, where_predicates); } } // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` Meta(List(m)) if m.path == BOUND => { if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { ser_bound.set_opt(&m.path, ser); de_bound.set_opt(&m.path, de); } } // Parse `#[serde(untagged)]` Meta(Path(word)) if word == UNTAGGED => match item.data { syn::Data::Enum(_) => { untagged.set_true(word); } syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { cx.error_spanned_by( struct_token, "#[serde(untagged)] can only be used on enums", ); } syn::Data::Union(syn::DataUnion { union_token, .. }) => { cx.error_spanned_by( union_token, "#[serde(untagged)] can only be used on enums", ); } }, // Parse `#[serde(tag = "type")]` Meta(NameValue(m)) if m.path == TAG => { if let Ok(s) = get_lit_str(cx, TAG, &m.lit) { match &item.data { syn::Data::Enum(_) => { internal_tag.set(&m.path, s.value()); } syn::Data::Struct(syn::DataStruct { fields, .. }) => match fields { syn::Fields::Named(_) => { internal_tag.set(&m.path, s.value()); } syn::Fields::Unnamed(_) | syn::Fields::Unit => { cx.error_spanned_by( fields, "#[serde(tag = \"...\")] can only be used on enums and structs with named fields", ); } }, syn::Data::Union(syn::DataUnion { union_token, .. }) => { cx.error_spanned_by( union_token, "#[serde(tag = \"...\")] can only be used on enums and structs with named fields", ); } } } } // Parse `#[serde(content = "c")]` Meta(NameValue(m)) if m.path == CONTENT => { if let Ok(s) = get_lit_str(cx, CONTENT, &m.lit) { match &item.data { syn::Data::Enum(_) => { content.set(&m.path, s.value()); } syn::Data::Struct(syn::DataStruct { struct_token, .. }) => { cx.error_spanned_by( struct_token, "#[serde(content = \"...\")] can only be used on enums", ); } syn::Data::Union(syn::DataUnion { union_token, .. }) => { cx.error_spanned_by( union_token, "#[serde(content = \"...\")] can only be used on enums", ); } } } } // Parse `#[serde(from = "Type")] Meta(NameValue(m)) if m.path == FROM => { if let Ok(from_ty) = parse_lit_into_ty(cx, FROM, &m.lit) { type_from.set_opt(&m.path, Some(from_ty)); } } // Parse `#[serde(try_from = "Type")] Meta(NameValue(m)) if m.path == TRY_FROM => { if let Ok(try_from_ty) = parse_lit_into_ty(cx, TRY_FROM, &m.lit) { type_try_from.set_opt(&m.path, Some(try_from_ty)); } } // Parse `#[serde(into = "Type")] Meta(NameValue(m)) if m.path == INTO => { if let Ok(into_ty) = parse_lit_into_ty(cx, INTO, &m.lit) { type_into.set_opt(&m.path, Some(into_ty)); } } // Parse `#[serde(remote = "...")]` Meta(NameValue(m)) if m.path == REMOTE => { if let Ok(path) = parse_lit_into_path(cx, REMOTE, &m.lit) { if is_primitive_path(&path, "Self") { remote.set(&m.path, item.ident.clone().into()); } else { remote.set(&m.path, path); } } } // Parse `#[serde(field_identifier)]` Meta(Path(word)) if word == FIELD_IDENTIFIER => { field_identifier.set_true(word); } // Parse `#[serde(variant_identifier)]` Meta(Path(word)) if word == VARIANT_IDENTIFIER => { variant_identifier.set_true(word); } // Parse `#[serde(crate = "foo")]` Meta(NameValue(m)) if m.path == CRATE => { if let Ok(path) = parse_lit_into_path(cx, CRATE, &m.lit) { serde_path.set(&m.path, path) } } // Parse `#[serde(expecting = "a message")]` Meta(NameValue(m)) if m.path == EXPECTING => { if let Ok(s) = get_lit_str(cx, EXPECTING, &m.lit) { expecting.set(&m.path, s.value()); } } Meta(meta_item) => { let path = meta_item .path() .into_token_stream() .to_string() .replace(' ', ""); cx.error_spanned_by( meta_item.path(), format!("unknown serde container attribute `{}`", path), ); } Lit(lit) => { cx.error_spanned_by(lit, "unexpected literal in serde container attribute"); } } } let mut is_packed = false; for attr in &item.attrs { if attr.path.is_ident("repr") { let _ = attr.parse_args_with(|input: ParseStream| { while let Some(token) = input.parse()? { if let TokenTree::Ident(ident) = token { is_packed |= ident == "packed"; } } Ok(()) }); } } Container { name: Name::from_attrs(unraw(&item.ident), ser_name, de_name, None), transparent: transparent.get(), deny_unknown_fields: deny_unknown_fields.get(), default: default.get().unwrap_or(Default::None), rename_all_rules: RenameAllRules { serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), }, ser_bound: ser_bound.get(), de_bound: de_bound.get(), tag: decide_tag(cx, item, untagged, internal_tag, content), type_from: type_from.get(), type_try_from: type_try_from.get(), type_into: type_into.get(), remote: remote.get(), identifier: decide_identifier(cx, item, field_identifier, variant_identifier), has_flatten: false, serde_path: serde_path.get(), is_packed, expecting: expecting.get(), } } pub fn name(&self) -> &Name { &self.name } pub fn rename_all_rules(&self) -> &RenameAllRules { &self.rename_all_rules } pub fn transparent(&self) -> bool { self.transparent } pub fn deny_unknown_fields(&self) -> bool { self.deny_unknown_fields } pub fn default(&self) -> &Default { &self.default } pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { self.ser_bound.as_ref().map(|vec| &vec[..]) } pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { self.de_bound.as_ref().map(|vec| &vec[..]) } pub fn tag(&self) -> &TagType { &self.tag } pub fn type_from(&self) -> Option<&syn::Type> { self.type_from.as_ref() } pub fn type_try_from(&self) -> Option<&syn::Type> { self.type_try_from.as_ref() } pub fn type_into(&self) -> Option<&syn::Type> { self.type_into.as_ref() } pub fn remote(&self) -> Option<&syn::Path> { self.remote.as_ref() } pub fn is_packed(&self) -> bool { self.is_packed } pub fn identifier(&self) -> Identifier { self.identifier } pub fn has_flatten(&self) -> bool { self.has_flatten } pub fn mark_has_flatten(&mut self) { self.has_flatten = true; } pub fn custom_serde_path(&self) -> Option<&syn::Path> { self.serde_path.as_ref() } pub fn serde_path(&self) -> Cow { self.custom_serde_path() .map_or_else(|| Cow::Owned(parse_quote!(_serde)), Cow::Borrowed) } /// Error message generated when type can't be deserialized. /// If `None`, default message will be used pub fn expecting(&self) -> Option<&str> { self.expecting.as_ref().map(String::as_ref) } } fn decide_tag( cx: &Ctxt, item: &syn::DeriveInput, untagged: BoolAttr, internal_tag: Attr, content: Attr, ) -> TagType { match ( untagged.0.get_with_tokens(), internal_tag.get_with_tokens(), content.get_with_tokens(), ) { (None, None, None) => TagType::External, (Some(_), None, None) => TagType::None, (None, Some((_, tag)), None) => { // Check that there are no tuple variants. if let syn::Data::Enum(data) = &item.data { for variant in &data.variants { match &variant.fields { syn::Fields::Named(_) | syn::Fields::Unit => {} syn::Fields::Unnamed(fields) => { if fields.unnamed.len() != 1 { cx.error_spanned_by( variant, "#[serde(tag = \"...\")] cannot be used with tuple variants", ); break; } } } } } TagType::Internal { tag } } (Some((untagged_tokens, _)), Some((tag_tokens, _)), None) => { cx.error_spanned_by( untagged_tokens, "enum cannot be both untagged and internally tagged", ); cx.error_spanned_by( tag_tokens, "enum cannot be both untagged and internally tagged", ); TagType::External // doesn't matter, will error } (None, None, Some((content_tokens, _))) => { cx.error_spanned_by( content_tokens, "#[serde(tag = \"...\", content = \"...\")] must be used together", ); TagType::External } (Some((untagged_tokens, _)), None, Some((content_tokens, _))) => { cx.error_spanned_by( untagged_tokens, "untagged enum cannot have #[serde(content = \"...\")]", ); cx.error_spanned_by( content_tokens, "untagged enum cannot have #[serde(content = \"...\")]", ); TagType::External } (None, Some((_, tag)), Some((_, content))) => TagType::Adjacent { tag, content }, (Some((untagged_tokens, _)), Some((tag_tokens, _)), Some((content_tokens, _))) => { cx.error_spanned_by( untagged_tokens, "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", ); cx.error_spanned_by( tag_tokens, "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", ); cx.error_spanned_by( content_tokens, "untagged enum cannot have #[serde(tag = \"...\", content = \"...\")]", ); TagType::External } } } fn decide_identifier( cx: &Ctxt, item: &syn::DeriveInput, field_identifier: BoolAttr, variant_identifier: BoolAttr, ) -> Identifier { match ( &item.data, field_identifier.0.get_with_tokens(), variant_identifier.0.get_with_tokens(), ) { (_, None, None) => Identifier::No, (_, Some((field_identifier_tokens, _)), Some((variant_identifier_tokens, _))) => { cx.error_spanned_by( field_identifier_tokens, "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", ); cx.error_spanned_by( variant_identifier_tokens, "#[serde(field_identifier)] and #[serde(variant_identifier)] cannot both be set", ); Identifier::No } (syn::Data::Enum(_), Some(_), None) => Identifier::Field, (syn::Data::Enum(_), None, Some(_)) => Identifier::Variant, (syn::Data::Struct(syn::DataStruct { struct_token, .. }), Some(_), None) => { cx.error_spanned_by( struct_token, "#[serde(field_identifier)] can only be used on an enum", ); Identifier::No } (syn::Data::Union(syn::DataUnion { union_token, .. }), Some(_), None) => { cx.error_spanned_by( union_token, "#[serde(field_identifier)] can only be used on an enum", ); Identifier::No } (syn::Data::Struct(syn::DataStruct { struct_token, .. }), None, Some(_)) => { cx.error_spanned_by( struct_token, "#[serde(variant_identifier)] can only be used on an enum", ); Identifier::No } (syn::Data::Union(syn::DataUnion { union_token, .. }), None, Some(_)) => { cx.error_spanned_by( union_token, "#[serde(variant_identifier)] can only be used on an enum", ); Identifier::No } } } /// Represents variant attribute information pub struct Variant { name: Name, rename_all_rules: RenameAllRules, ser_bound: Option>, de_bound: Option>, skip_deserializing: bool, skip_serializing: bool, other: bool, serialize_with: Option, deserialize_with: Option, borrow: Option, } impl Variant { pub fn from_ast(cx: &Ctxt, variant: &syn::Variant) -> Self { let mut ser_name = Attr::none(cx, RENAME); let mut de_name = Attr::none(cx, RENAME); let mut de_aliases = VecAttr::none(cx, RENAME); let mut skip_deserializing = BoolAttr::none(cx, SKIP_DESERIALIZING); let mut skip_serializing = BoolAttr::none(cx, SKIP_SERIALIZING); let mut rename_all_ser_rule = Attr::none(cx, RENAME_ALL); let mut rename_all_de_rule = Attr::none(cx, RENAME_ALL); let mut ser_bound = Attr::none(cx, BOUND); let mut de_bound = Attr::none(cx, BOUND); let mut other = BoolAttr::none(cx, OTHER); let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); let mut borrow = Attr::none(cx, BORROW); for meta_item in variant .attrs .iter() .flat_map(|attr| get_serde_meta_items(cx, attr)) .flatten() { match &meta_item { // Parse `#[serde(rename = "foo")]` Meta(NameValue(m)) if m.path == RENAME => { if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { ser_name.set(&m.path, s.value()); de_name.set_if_none(s.value()); de_aliases.insert(&m.path, s.value()); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` Meta(List(m)) if m.path == RENAME => { if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) { ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); for de_value in de { de_name.set_if_none(de_value.value()); de_aliases.insert(&m.path, de_value.value()); } } } // Parse `#[serde(alias = "foo")]` Meta(NameValue(m)) if m.path == ALIAS => { if let Ok(s) = get_lit_str(cx, ALIAS, &m.lit) { de_aliases.insert(&m.path, s.value()); } } // Parse `#[serde(rename_all = "foo")]` Meta(NameValue(m)) if m.path == RENAME_ALL => { if let Ok(s) = get_lit_str(cx, RENAME_ALL, &m.lit) { match RenameRule::from_str(&s.value()) { Ok(rename_rule) => { rename_all_ser_rule.set(&m.path, rename_rule); rename_all_de_rule.set(&m.path, rename_rule); } Err(err) => cx.error_spanned_by(s, err), } } } // Parse `#[serde(rename_all(serialize = "foo", deserialize = "bar"))]` Meta(List(m)) if m.path == RENAME_ALL => { if let Ok((ser, de)) = get_renames(cx, &m.nested) { if let Some(ser) = ser { match RenameRule::from_str(&ser.value()) { Ok(rename_rule) => rename_all_ser_rule.set(&m.path, rename_rule), Err(err) => cx.error_spanned_by(ser, err), } } if let Some(de) = de { match RenameRule::from_str(&de.value()) { Ok(rename_rule) => rename_all_de_rule.set(&m.path, rename_rule), Err(err) => cx.error_spanned_by(de, err), } } } } // Parse `#[serde(skip)]` Meta(Path(word)) if word == SKIP => { skip_serializing.set_true(word); skip_deserializing.set_true(word); } // Parse `#[serde(skip_deserializing)]` Meta(Path(word)) if word == SKIP_DESERIALIZING => { skip_deserializing.set_true(word); } // Parse `#[serde(skip_serializing)]` Meta(Path(word)) if word == SKIP_SERIALIZING => { skip_serializing.set_true(word); } // Parse `#[serde(other)]` Meta(Path(word)) if word == OTHER => { other.set_true(word); } // Parse `#[serde(bound = "T: SomeBound")]` Meta(NameValue(m)) if m.path == BOUND => { if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { ser_bound.set(&m.path, where_predicates.clone()); de_bound.set(&m.path, where_predicates); } } // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` Meta(List(m)) if m.path == BOUND => { if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { ser_bound.set_opt(&m.path, ser); de_bound.set_opt(&m.path, de); } } // Parse `#[serde(with = "...")]` Meta(NameValue(m)) if m.path == WITH => { if let Ok(path) = parse_lit_into_expr_path(cx, WITH, &m.lit) { let mut ser_path = path.clone(); ser_path .path .segments .push(Ident::new("serialize", Span::call_site()).into()); serialize_with.set(&m.path, ser_path); let mut de_path = path; de_path .path .segments .push(Ident::new("deserialize", Span::call_site()).into()); deserialize_with.set(&m.path, de_path); } } // Parse `#[serde(serialize_with = "...")]` Meta(NameValue(m)) if m.path == SERIALIZE_WITH => { if let Ok(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &m.lit) { serialize_with.set(&m.path, path); } } // Parse `#[serde(deserialize_with = "...")]` Meta(NameValue(m)) if m.path == DESERIALIZE_WITH => { if let Ok(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &m.lit) { deserialize_with.set(&m.path, path); } } // Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]` Meta(m) if m.path() == BORROW => match &variant.fields { syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { borrow.set(m.path(), m.clone()); } _ => { cx.error_spanned_by( variant, "#[serde(borrow)] may only be used on newtype variants", ); } }, Meta(meta_item) => { let path = meta_item .path() .into_token_stream() .to_string() .replace(' ', ""); cx.error_spanned_by( meta_item.path(), format!("unknown serde variant attribute `{}`", path), ); } Lit(lit) => { cx.error_spanned_by(lit, "unexpected literal in serde variant attribute"); } } } Variant { name: Name::from_attrs(unraw(&variant.ident), ser_name, de_name, Some(de_aliases)), rename_all_rules: RenameAllRules { serialize: rename_all_ser_rule.get().unwrap_or(RenameRule::None), deserialize: rename_all_de_rule.get().unwrap_or(RenameRule::None), }, ser_bound: ser_bound.get(), de_bound: de_bound.get(), skip_deserializing: skip_deserializing.get(), skip_serializing: skip_serializing.get(), other: other.get(), serialize_with: serialize_with.get(), deserialize_with: deserialize_with.get(), borrow: borrow.get(), } } pub fn name(&self) -> &Name { &self.name } pub fn aliases(&self) -> Vec { self.name.deserialize_aliases() } pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { if !self.name.serialize_renamed { self.name.serialize = rules.serialize.apply_to_variant(&self.name.serialize); } if !self.name.deserialize_renamed { self.name.deserialize = rules.deserialize.apply_to_variant(&self.name.deserialize); } } pub fn rename_all_rules(&self) -> &RenameAllRules { &self.rename_all_rules } pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { self.ser_bound.as_ref().map(|vec| &vec[..]) } pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { self.de_bound.as_ref().map(|vec| &vec[..]) } pub fn skip_deserializing(&self) -> bool { self.skip_deserializing } pub fn skip_serializing(&self) -> bool { self.skip_serializing } pub fn other(&self) -> bool { self.other } pub fn serialize_with(&self) -> Option<&syn::ExprPath> { self.serialize_with.as_ref() } pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { self.deserialize_with.as_ref() } } /// Represents field attribute information pub struct Field { name: Name, skip_serializing: bool, skip_deserializing: bool, skip_serializing_if: Option, default: Default, serialize_with: Option, deserialize_with: Option, ser_bound: Option>, de_bound: Option>, borrowed_lifetimes: BTreeSet, getter: Option, flatten: bool, transparent: bool, } /// Represents the default to use for a field when deserializing. pub enum Default { /// Field must always be specified because it does not have a default. None, /// The default is given by `std::default::Default::default()`. Default, /// The default is given by this function. Path(syn::ExprPath), } impl Default { pub fn is_none(&self) -> bool { match self { Default::None => true, Default::Default | Default::Path(_) => false, } } } impl Field { /// Extract out the `#[serde(...)]` attributes from a struct field. pub fn from_ast( cx: &Ctxt, index: usize, field: &syn::Field, attrs: Option<&Variant>, container_default: &Default, ) -> Self { let mut ser_name = Attr::none(cx, RENAME); let mut de_name = Attr::none(cx, RENAME); let mut de_aliases = VecAttr::none(cx, RENAME); let mut skip_serializing = BoolAttr::none(cx, SKIP_SERIALIZING); let mut skip_deserializing = BoolAttr::none(cx, SKIP_DESERIALIZING); let mut skip_serializing_if = Attr::none(cx, SKIP_SERIALIZING_IF); let mut default = Attr::none(cx, DEFAULT); let mut serialize_with = Attr::none(cx, SERIALIZE_WITH); let mut deserialize_with = Attr::none(cx, DESERIALIZE_WITH); let mut ser_bound = Attr::none(cx, BOUND); let mut de_bound = Attr::none(cx, BOUND); let mut borrowed_lifetimes = Attr::none(cx, BORROW); let mut getter = Attr::none(cx, GETTER); let mut flatten = BoolAttr::none(cx, FLATTEN); let ident = match &field.ident { Some(ident) => unraw(ident), None => index.to_string(), }; let variant_borrow = attrs .and_then(|variant| variant.borrow.as_ref()) .map(|borrow| Meta(borrow.clone())); for meta_item in field .attrs .iter() .flat_map(|attr| get_serde_meta_items(cx, attr)) .flatten() .chain(variant_borrow) { match &meta_item { // Parse `#[serde(rename = "foo")]` Meta(NameValue(m)) if m.path == RENAME => { if let Ok(s) = get_lit_str(cx, RENAME, &m.lit) { ser_name.set(&m.path, s.value()); de_name.set_if_none(s.value()); de_aliases.insert(&m.path, s.value()); } } // Parse `#[serde(rename(serialize = "foo", deserialize = "bar"))]` Meta(List(m)) if m.path == RENAME => { if let Ok((ser, de)) = get_multiple_renames(cx, &m.nested) { ser_name.set_opt(&m.path, ser.map(syn::LitStr::value)); for de_value in de { de_name.set_if_none(de_value.value()); de_aliases.insert(&m.path, de_value.value()); } } } // Parse `#[serde(alias = "foo")]` Meta(NameValue(m)) if m.path == ALIAS => { if let Ok(s) = get_lit_str(cx, ALIAS, &m.lit) { de_aliases.insert(&m.path, s.value()); } } // Parse `#[serde(default)]` Meta(Path(word)) if word == DEFAULT => { default.set(word, Default::Default); } // Parse `#[serde(default = "...")]` Meta(NameValue(m)) if m.path == DEFAULT => { if let Ok(path) = parse_lit_into_expr_path(cx, DEFAULT, &m.lit) { default.set(&m.path, Default::Path(path)); } } // Parse `#[serde(skip_serializing)]` Meta(Path(word)) if word == SKIP_SERIALIZING => { skip_serializing.set_true(word); } // Parse `#[serde(skip_deserializing)]` Meta(Path(word)) if word == SKIP_DESERIALIZING => { skip_deserializing.set_true(word); } // Parse `#[serde(skip)]` Meta(Path(word)) if word == SKIP => { skip_serializing.set_true(word); skip_deserializing.set_true(word); } // Parse `#[serde(skip_serializing_if = "...")]` Meta(NameValue(m)) if m.path == SKIP_SERIALIZING_IF => { if let Ok(path) = parse_lit_into_expr_path(cx, SKIP_SERIALIZING_IF, &m.lit) { skip_serializing_if.set(&m.path, path); } } // Parse `#[serde(serialize_with = "...")]` Meta(NameValue(m)) if m.path == SERIALIZE_WITH => { if let Ok(path) = parse_lit_into_expr_path(cx, SERIALIZE_WITH, &m.lit) { serialize_with.set(&m.path, path); } } // Parse `#[serde(deserialize_with = "...")]` Meta(NameValue(m)) if m.path == DESERIALIZE_WITH => { if let Ok(path) = parse_lit_into_expr_path(cx, DESERIALIZE_WITH, &m.lit) { deserialize_with.set(&m.path, path); } } // Parse `#[serde(with = "...")]` Meta(NameValue(m)) if m.path == WITH => { if let Ok(path) = parse_lit_into_expr_path(cx, WITH, &m.lit) { let mut ser_path = path.clone(); ser_path .path .segments .push(Ident::new("serialize", Span::call_site()).into()); serialize_with.set(&m.path, ser_path); let mut de_path = path; de_path .path .segments .push(Ident::new("deserialize", Span::call_site()).into()); deserialize_with.set(&m.path, de_path); } } // Parse `#[serde(bound = "T: SomeBound")]` Meta(NameValue(m)) if m.path == BOUND => { if let Ok(where_predicates) = parse_lit_into_where(cx, BOUND, BOUND, &m.lit) { ser_bound.set(&m.path, where_predicates.clone()); de_bound.set(&m.path, where_predicates); } } // Parse `#[serde(bound(serialize = "...", deserialize = "..."))]` Meta(List(m)) if m.path == BOUND => { if let Ok((ser, de)) = get_where_predicates(cx, &m.nested) { ser_bound.set_opt(&m.path, ser); de_bound.set_opt(&m.path, de); } } // Parse `#[serde(borrow)]` Meta(Path(word)) if word == BORROW => { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { borrowed_lifetimes.set(word, borrowable); } } // Parse `#[serde(borrow = "'a + 'b")]` Meta(NameValue(m)) if m.path == BORROW => { if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, BORROW, &m.lit) { if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) { for lifetime in &lifetimes { if !borrowable.contains(lifetime) { cx.error_spanned_by( field, format!( "field `{}` does not have lifetime {}", ident, lifetime ), ); } } borrowed_lifetimes.set(&m.path, lifetimes); } } } // Parse `#[serde(getter = "...")]` Meta(NameValue(m)) if m.path == GETTER => { if let Ok(path) = parse_lit_into_expr_path(cx, GETTER, &m.lit) { getter.set(&m.path, path); } } // Parse `#[serde(flatten)]` Meta(Path(word)) if word == FLATTEN => { flatten.set_true(word); } Meta(meta_item) => { let path = meta_item .path() .into_token_stream() .to_string() .replace(' ', ""); cx.error_spanned_by( meta_item.path(), format!("unknown serde field attribute `{}`", path), ); } Lit(lit) => { cx.error_spanned_by(lit, "unexpected literal in serde field attribute"); } } } // Is skip_deserializing, initialize the field to Default::default() unless a // different default is specified by `#[serde(default = "...")]` on // ourselves or our container (e.g. the struct we are in). if let Default::None = *container_default { if skip_deserializing.0.value.is_some() { default.set_if_none(Default::Default); } } let mut borrowed_lifetimes = borrowed_lifetimes.get().unwrap_or_default(); if !borrowed_lifetimes.is_empty() { // Cow and Cow<[u8]> never borrow by default: // // impl<'de, 'a, T: ?Sized> Deserialize<'de> for Cow<'a, T> // // A #[serde(borrow)] attribute enables borrowing that corresponds // roughly to these impls: // // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, str> // impl<'de: 'a, 'a> Deserialize<'de> for Cow<'a, [u8]> if is_cow(&field.ty, is_str) { let mut path = syn::Path { leading_colon: None, segments: Punctuated::new(), }; let span = Span::call_site(); path.segments.push(Ident::new("_serde", span).into()); path.segments.push(Ident::new("__private", span).into()); path.segments.push(Ident::new("de", span).into()); path.segments .push(Ident::new("borrow_cow_str", span).into()); let expr = syn::ExprPath { attrs: Vec::new(), qself: None, path, }; deserialize_with.set_if_none(expr); } else if is_cow(&field.ty, is_slice_u8) { let mut path = syn::Path { leading_colon: None, segments: Punctuated::new(), }; let span = Span::call_site(); path.segments.push(Ident::new("_serde", span).into()); path.segments.push(Ident::new("__private", span).into()); path.segments.push(Ident::new("de", span).into()); path.segments .push(Ident::new("borrow_cow_bytes", span).into()); let expr = syn::ExprPath { attrs: Vec::new(), qself: None, path, }; deserialize_with.set_if_none(expr); } } else if is_implicitly_borrowed(&field.ty) { // Types &str and &[u8] are always implicitly borrowed. No need for // a #[serde(borrow)]. collect_lifetimes(&field.ty, &mut borrowed_lifetimes); } Field { name: Name::from_attrs(ident, ser_name, de_name, Some(de_aliases)), skip_serializing: skip_serializing.get(), skip_deserializing: skip_deserializing.get(), skip_serializing_if: skip_serializing_if.get(), default: default.get().unwrap_or(Default::None), serialize_with: serialize_with.get(), deserialize_with: deserialize_with.get(), ser_bound: ser_bound.get(), de_bound: de_bound.get(), borrowed_lifetimes, getter: getter.get(), flatten: flatten.get(), transparent: false, } } pub fn name(&self) -> &Name { &self.name } pub fn aliases(&self) -> Vec { self.name.deserialize_aliases() } pub fn rename_by_rules(&mut self, rules: &RenameAllRules) { if !self.name.serialize_renamed { self.name.serialize = rules.serialize.apply_to_field(&self.name.serialize); } if !self.name.deserialize_renamed { self.name.deserialize = rules.deserialize.apply_to_field(&self.name.deserialize); } } pub fn skip_serializing(&self) -> bool { self.skip_serializing } pub fn skip_deserializing(&self) -> bool { self.skip_deserializing } pub fn skip_serializing_if(&self) -> Option<&syn::ExprPath> { self.skip_serializing_if.as_ref() } pub fn default(&self) -> &Default { &self.default } pub fn serialize_with(&self) -> Option<&syn::ExprPath> { self.serialize_with.as_ref() } pub fn deserialize_with(&self) -> Option<&syn::ExprPath> { self.deserialize_with.as_ref() } pub fn ser_bound(&self) -> Option<&[syn::WherePredicate]> { self.ser_bound.as_ref().map(|vec| &vec[..]) } pub fn de_bound(&self) -> Option<&[syn::WherePredicate]> { self.de_bound.as_ref().map(|vec| &vec[..]) } pub fn borrowed_lifetimes(&self) -> &BTreeSet { &self.borrowed_lifetimes } pub fn getter(&self) -> Option<&syn::ExprPath> { self.getter.as_ref() } pub fn flatten(&self) -> bool { self.flatten } pub fn transparent(&self) -> bool { self.transparent } pub fn mark_transparent(&mut self) { self.transparent = true; } } type SerAndDe = (Option, Option); fn get_ser_and_de<'a, 'b, T, F>( cx: &'b Ctxt, attr_name: Symbol, metas: &'a Punctuated, f: F, ) -> Result<(VecAttr<'b, T>, VecAttr<'b, T>), ()> where T: 'a, F: Fn(&Ctxt, Symbol, Symbol, &'a syn::Lit) -> Result, { let mut ser_meta = VecAttr::none(cx, attr_name); let mut de_meta = VecAttr::none(cx, attr_name); for meta in metas { match meta { Meta(NameValue(meta)) if meta.path == SERIALIZE => { if let Ok(v) = f(cx, attr_name, SERIALIZE, &meta.lit) { ser_meta.insert(&meta.path, v); } } Meta(NameValue(meta)) if meta.path == DESERIALIZE => { if let Ok(v) = f(cx, attr_name, DESERIALIZE, &meta.lit) { de_meta.insert(&meta.path, v); } } _ => { cx.error_spanned_by( meta, format!( "malformed {0} attribute, expected `{0}(serialize = ..., deserialize = ...)`", attr_name ), ); return Err(()); } } } Ok((ser_meta, de_meta)) } fn get_renames<'a>( cx: &Ctxt, items: &'a Punctuated, ) -> Result, ()> { let (ser, de) = get_ser_and_de(cx, RENAME, items, get_lit_str2)?; Ok((ser.at_most_one()?, de.at_most_one()?)) } fn get_multiple_renames<'a>( cx: &Ctxt, items: &'a Punctuated, ) -> Result<(Option<&'a syn::LitStr>, Vec<&'a syn::LitStr>), ()> { let (ser, de) = get_ser_and_de(cx, RENAME, items, get_lit_str2)?; Ok((ser.at_most_one()?, de.get())) } fn get_where_predicates( cx: &Ctxt, items: &Punctuated, ) -> Result>, ()> { let (ser, de) = get_ser_and_de(cx, BOUND, items, parse_lit_into_where)?; Ok((ser.at_most_one()?, de.at_most_one()?)) } pub fn get_serde_meta_items(cx: &Ctxt, attr: &syn::Attribute) -> Result, ()> { if attr.path != SERDE { return Ok(Vec::new()); } match attr.parse_meta() { Ok(List(meta)) => Ok(meta.nested.into_iter().collect()), Ok(other) => { cx.error_spanned_by(other, "expected #[serde(...)]"); Err(()) } Err(err) => { cx.syn_error(err); Err(()) } } } fn get_lit_str<'a>(cx: &Ctxt, attr_name: Symbol, lit: &'a syn::Lit) -> Result<&'a syn::LitStr, ()> { get_lit_str2(cx, attr_name, attr_name, lit) } fn get_lit_str2<'a>( cx: &Ctxt, attr_name: Symbol, meta_item_name: Symbol, lit: &'a syn::Lit, ) -> Result<&'a syn::LitStr, ()> { if let syn::Lit::Str(lit) = lit { Ok(lit) } else { cx.error_spanned_by( lit, format!( "expected serde {} attribute to be a string: `{} = \"...\"`", attr_name, meta_item_name ), ); Err(()) } } fn parse_lit_into_path(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result { let string = get_lit_str(cx, attr_name, lit)?; parse_lit_str(string).map_err(|_| { cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())) }) } fn parse_lit_into_expr_path( cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit, ) -> Result { let string = get_lit_str(cx, attr_name, lit)?; parse_lit_str(string).map_err(|_| { cx.error_spanned_by(lit, format!("failed to parse path: {:?}", string.value())) }) } fn parse_lit_into_where( cx: &Ctxt, attr_name: Symbol, meta_item_name: Symbol, lit: &syn::Lit, ) -> Result, ()> { let string = get_lit_str2(cx, attr_name, meta_item_name, lit)?; if string.value().is_empty() { return Ok(Vec::new()); } let where_string = syn::LitStr::new(&format!("where {}", string.value()), string.span()); parse_lit_str::(&where_string) .map(|wh| wh.predicates.into_iter().collect()) .map_err(|err| cx.error_spanned_by(lit, err)) } fn parse_lit_into_ty(cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit) -> Result { let string = get_lit_str(cx, attr_name, lit)?; parse_lit_str(string).map_err(|_| { cx.error_spanned_by( lit, format!("failed to parse type: {} = {:?}", attr_name, string.value()), ) }) } // Parses a string literal like "'a + 'b + 'c" containing a nonempty list of // lifetimes separated by `+`. fn parse_lit_into_lifetimes( cx: &Ctxt, attr_name: Symbol, lit: &syn::Lit, ) -> Result, ()> { let string = get_lit_str(cx, attr_name, lit)?; if string.value().is_empty() { cx.error_spanned_by(lit, "at least one lifetime must be borrowed"); return Err(()); } struct BorrowedLifetimes(Punctuated); impl Parse for BorrowedLifetimes { fn parse(input: ParseStream) -> parse::Result { Punctuated::parse_separated_nonempty(input).map(BorrowedLifetimes) } } if let Ok(BorrowedLifetimes(lifetimes)) = parse_lit_str(string) { let mut set = BTreeSet::new(); for lifetime in lifetimes { if !set.insert(lifetime.clone()) { cx.error_spanned_by(lit, format!("duplicate borrowed lifetime `{}`", lifetime)); } } return Ok(set); } cx.error_spanned_by( lit, format!("failed to parse borrowed lifetimes: {:?}", string.value()), ); Err(()) } fn is_implicitly_borrowed(ty: &syn::Type) -> bool { is_implicitly_borrowed_reference(ty) || is_option(ty, is_implicitly_borrowed_reference) } fn is_implicitly_borrowed_reference(ty: &syn::Type) -> bool { is_reference(ty, is_str) || is_reference(ty, is_slice_u8) } // Whether the type looks like it might be `std::borrow::Cow` where elem="T". // This can have false negatives and false positives. // // False negative: // // use std::borrow::Cow as Pig; // // #[derive(Deserialize)] // struct S<'a> { // #[serde(borrow)] // pig: Pig<'a, str>, // } // // False positive: // // type str = [i16]; // // #[derive(Deserialize)] // struct S<'a> { // #[serde(borrow)] // cow: Cow<'a, str>, // } fn is_cow(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { let path = match ungroup(ty) { syn::Type::Path(ty) => &ty.path, _ => { return false; } }; let seg = match path.segments.last() { Some(seg) => seg, None => { return false; } }; let args = match &seg.arguments { syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, _ => { return false; } }; seg.ident == "Cow" && args.len() == 2 && match (&args[0], &args[1]) { (syn::GenericArgument::Lifetime(_), syn::GenericArgument::Type(arg)) => elem(arg), _ => false, } } fn is_option(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { let path = match ungroup(ty) { syn::Type::Path(ty) => &ty.path, _ => { return false; } }; let seg = match path.segments.last() { Some(seg) => seg, None => { return false; } }; let args = match &seg.arguments { syn::PathArguments::AngleBracketed(bracketed) => &bracketed.args, _ => { return false; } }; seg.ident == "Option" && args.len() == 1 && match &args[0] { syn::GenericArgument::Type(arg) => elem(arg), _ => false, } } // Whether the type looks like it might be `&T` where elem="T". This can have // false negatives and false positives. // // False negative: // // type Yarn = str; // // #[derive(Deserialize)] // struct S<'a> { // r: &'a Yarn, // } // // False positive: // // type str = [i16]; // // #[derive(Deserialize)] // struct S<'a> { // r: &'a str, // } fn is_reference(ty: &syn::Type, elem: fn(&syn::Type) -> bool) -> bool { match ungroup(ty) { syn::Type::Reference(ty) => ty.mutability.is_none() && elem(&ty.elem), _ => false, } } fn is_str(ty: &syn::Type) -> bool { is_primitive_type(ty, "str") } fn is_slice_u8(ty: &syn::Type) -> bool { match ungroup(ty) { syn::Type::Slice(ty) => is_primitive_type(&ty.elem, "u8"), _ => false, } } fn is_primitive_type(ty: &syn::Type, primitive: &str) -> bool { match ungroup(ty) { syn::Type::Path(ty) => ty.qself.is_none() && is_primitive_path(&ty.path, primitive), _ => false, } } fn is_primitive_path(path: &syn::Path, primitive: &str) -> bool { path.leading_colon.is_none() && path.segments.len() == 1 && path.segments[0].ident == primitive && path.segments[0].arguments.is_empty() } // All lifetimes that this type could borrow from a Deserializer. // // For example a type `S<'a, 'b>` could borrow `'a` and `'b`. On the other hand // a type `for<'a> fn(&'a str)` could not borrow `'a` from the Deserializer. // // This is used when there is an explicit or implicit `#[serde(borrow)]` // attribute on the field so there must be at least one borrowable lifetime. fn borrowable_lifetimes( cx: &Ctxt, name: &str, field: &syn::Field, ) -> Result, ()> { let mut lifetimes = BTreeSet::new(); collect_lifetimes(&field.ty, &mut lifetimes); if lifetimes.is_empty() { cx.error_spanned_by( field, format!("field `{}` has no lifetimes to borrow", name), ); Err(()) } else { Ok(lifetimes) } } fn collect_lifetimes(ty: &syn::Type, out: &mut BTreeSet) { match ty { syn::Type::Slice(ty) => { collect_lifetimes(&ty.elem, out); } syn::Type::Array(ty) => { collect_lifetimes(&ty.elem, out); } syn::Type::Ptr(ty) => { collect_lifetimes(&ty.elem, out); } syn::Type::Reference(ty) => { out.extend(ty.lifetime.iter().cloned()); collect_lifetimes(&ty.elem, out); } syn::Type::Tuple(ty) => { for elem in &ty.elems { collect_lifetimes(elem, out); } } syn::Type::Path(ty) => { if let Some(qself) = &ty.qself { collect_lifetimes(&qself.ty, out); } for seg in &ty.path.segments { if let syn::PathArguments::AngleBracketed(bracketed) = &seg.arguments { for arg in &bracketed.args { match arg { syn::GenericArgument::Lifetime(lifetime) => { out.insert(lifetime.clone()); } syn::GenericArgument::Type(ty) => { collect_lifetimes(ty, out); } syn::GenericArgument::Binding(binding) => { collect_lifetimes(&binding.ty, out); } syn::GenericArgument::Constraint(_) | syn::GenericArgument::Const(_) => {} } } } } } syn::Type::Paren(ty) => { collect_lifetimes(&ty.elem, out); } syn::Type::Group(ty) => { collect_lifetimes(&ty.elem, out); } syn::Type::Macro(ty) => { collect_lifetimes_from_tokens(ty.mac.tokens.clone(), out); } syn::Type::BareFn(_) | syn::Type::Never(_) | syn::Type::TraitObject(_) | syn::Type::ImplTrait(_) | syn::Type::Infer(_) | syn::Type::Verbatim(_) => {} #[cfg(test)] syn::Type::__TestExhaustive(_) => unimplemented!(), #[cfg(not(test))] _ => {} } } fn collect_lifetimes_from_tokens(tokens: TokenStream, out: &mut BTreeSet) { let mut iter = tokens.into_iter(); while let Some(tt) = iter.next() { match &tt { TokenTree::Punct(op) if op.as_char() == '\'' && op.spacing() == Spacing::Joint => { if let Some(TokenTree::Ident(ident)) = iter.next() { out.insert(syn::Lifetime { apostrophe: op.span(), ident, }); } } TokenTree::Group(group) => { let tokens = group.stream(); collect_lifetimes_from_tokens(tokens, out); } _ => {} } } } fn parse_lit_str(s: &syn::LitStr) -> parse::Result where T: Parse, { let tokens = spanned_tokens(s)?; syn::parse2(tokens) } fn spanned_tokens(s: &syn::LitStr) -> parse::Result { let stream = syn::parse_str(&s.value())?; Ok(respan(stream, s.span())) } serde_derive_internals-0.26.0/src/case.rs000064400000000000000000000156770000000000000164750ustar 00000000000000//! Code to convert the Rust-styled field/variant (e.g. `my_field`, `MyType`) to the //! case of the source (e.g. `my-field`, `MY_FIELD`). // See https://users.rust-lang.org/t/psa-dealing-with-warning-unused-import-std-ascii-asciiext-in-today-s-nightly/13726 #[allow(deprecated, unused_imports)] use std::ascii::AsciiExt; use std::fmt::{self, Debug, Display}; use self::RenameRule::*; /// The different possible ways to change case of fields in a struct, or variants in an enum. #[derive(Copy, Clone, PartialEq)] pub enum RenameRule { /// Don't apply a default rename rule. None, /// Rename direct children to "lowercase" style. LowerCase, /// Rename direct children to "UPPERCASE" style. UpperCase, /// Rename direct children to "PascalCase" style, as typically used for /// enum variants. PascalCase, /// Rename direct children to "camelCase" style. CamelCase, /// Rename direct children to "snake_case" style, as commonly used for /// fields. SnakeCase, /// Rename direct children to "SCREAMING_SNAKE_CASE" style, as commonly /// used for constants. ScreamingSnakeCase, /// Rename direct children to "kebab-case" style. KebabCase, /// Rename direct children to "SCREAMING-KEBAB-CASE" style. ScreamingKebabCase, } static RENAME_RULES: &[(&str, RenameRule)] = &[ ("lowercase", LowerCase), ("UPPERCASE", UpperCase), ("PascalCase", PascalCase), ("camelCase", CamelCase), ("snake_case", SnakeCase), ("SCREAMING_SNAKE_CASE", ScreamingSnakeCase), ("kebab-case", KebabCase), ("SCREAMING-KEBAB-CASE", ScreamingKebabCase), ]; impl RenameRule { pub fn from_str(rename_all_str: &str) -> Result { for (name, rule) in RENAME_RULES { if rename_all_str == *name { return Ok(*rule); } } Err(ParseError { unknown: rename_all_str, }) } /// Apply a renaming rule to an enum variant, returning the version expected in the source. pub fn apply_to_variant(&self, variant: &str) -> String { match *self { None | PascalCase => variant.to_owned(), LowerCase => variant.to_ascii_lowercase(), UpperCase => variant.to_ascii_uppercase(), CamelCase => variant[..1].to_ascii_lowercase() + &variant[1..], SnakeCase => { let mut snake = String::new(); for (i, ch) in variant.char_indices() { if i > 0 && ch.is_uppercase() { snake.push('_'); } snake.push(ch.to_ascii_lowercase()); } snake } ScreamingSnakeCase => SnakeCase.apply_to_variant(variant).to_ascii_uppercase(), KebabCase => SnakeCase.apply_to_variant(variant).replace('_', "-"), ScreamingKebabCase => ScreamingSnakeCase .apply_to_variant(variant) .replace('_', "-"), } } /// Apply a renaming rule to a struct field, returning the version expected in the source. pub fn apply_to_field(&self, field: &str) -> String { match *self { None | LowerCase | SnakeCase => field.to_owned(), UpperCase => field.to_ascii_uppercase(), PascalCase => { let mut pascal = String::new(); let mut capitalize = true; for ch in field.chars() { if ch == '_' { capitalize = true; } else if capitalize { pascal.push(ch.to_ascii_uppercase()); capitalize = false; } else { pascal.push(ch); } } pascal } CamelCase => { let pascal = PascalCase.apply_to_field(field); pascal[..1].to_ascii_lowercase() + &pascal[1..] } ScreamingSnakeCase => field.to_ascii_uppercase(), KebabCase => field.replace('_', "-"), ScreamingKebabCase => ScreamingSnakeCase.apply_to_field(field).replace('_', "-"), } } } pub struct ParseError<'a> { unknown: &'a str, } impl<'a> Display for ParseError<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("unknown rename rule `rename_all = ")?; Debug::fmt(self.unknown, f)?; f.write_str("`, expected one of ")?; for (i, (name, _rule)) in RENAME_RULES.iter().enumerate() { if i > 0 { f.write_str(", ")?; } Debug::fmt(name, f)?; } Ok(()) } } #[test] fn rename_variants() { for &(original, lower, upper, camel, snake, screaming, kebab, screaming_kebab) in &[ ( "Outcome", "outcome", "OUTCOME", "outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", ), ( "VeryTasty", "verytasty", "VERYTASTY", "veryTasty", "very_tasty", "VERY_TASTY", "very-tasty", "VERY-TASTY", ), ("A", "a", "A", "a", "a", "A", "a", "A"), ("Z42", "z42", "Z42", "z42", "z42", "Z42", "z42", "Z42"), ] { assert_eq!(None.apply_to_variant(original), original); assert_eq!(LowerCase.apply_to_variant(original), lower); assert_eq!(UpperCase.apply_to_variant(original), upper); assert_eq!(PascalCase.apply_to_variant(original), original); assert_eq!(CamelCase.apply_to_variant(original), camel); assert_eq!(SnakeCase.apply_to_variant(original), snake); assert_eq!(ScreamingSnakeCase.apply_to_variant(original), screaming); assert_eq!(KebabCase.apply_to_variant(original), kebab); assert_eq!( ScreamingKebabCase.apply_to_variant(original), screaming_kebab ); } } #[test] fn rename_fields() { for &(original, upper, pascal, camel, screaming, kebab, screaming_kebab) in &[ ( "outcome", "OUTCOME", "Outcome", "outcome", "OUTCOME", "outcome", "OUTCOME", ), ( "very_tasty", "VERY_TASTY", "VeryTasty", "veryTasty", "VERY_TASTY", "very-tasty", "VERY-TASTY", ), ("a", "A", "A", "a", "A", "a", "A"), ("z42", "Z42", "Z42", "z42", "Z42", "z42", "Z42"), ] { assert_eq!(None.apply_to_field(original), original); assert_eq!(UpperCase.apply_to_field(original), upper); assert_eq!(PascalCase.apply_to_field(original), pascal); assert_eq!(CamelCase.apply_to_field(original), camel); assert_eq!(SnakeCase.apply_to_field(original), original); assert_eq!(ScreamingSnakeCase.apply_to_field(original), screaming); assert_eq!(KebabCase.apply_to_field(original), kebab); assert_eq!(ScreamingKebabCase.apply_to_field(original), screaming_kebab); } } serde_derive_internals-0.26.0/src/check.rs000064400000000000000000000335720000000000000166310ustar 00000000000000use internals::ast::{Container, Data, Field, Style}; use internals::attr::{Identifier, TagType}; use internals::{ungroup, Ctxt, Derive}; use syn::{Member, Type}; /// Cross-cutting checks that require looking at more than a single attrs /// object. Simpler checks should happen when parsing and building the attrs. pub fn check(cx: &Ctxt, cont: &mut Container, derive: Derive) { check_getter(cx, cont); check_flatten(cx, cont); check_identifier(cx, cont); check_variant_skip_attrs(cx, cont); check_internal_tag_field_name_conflict(cx, cont); check_adjacent_tag_conflict(cx, cont); check_transparent(cx, cont, derive); check_from_and_try_from(cx, cont); } /// Getters are only allowed inside structs (not enums) with the `remote` /// attribute. fn check_getter(cx: &Ctxt, cont: &Container) { match cont.data { Data::Enum(_) => { if cont.data.has_getter() { cx.error_spanned_by( cont.original, "#[serde(getter = \"...\")] is not allowed in an enum", ); } } Data::Struct(_, _) => { if cont.data.has_getter() && cont.attrs.remote().is_none() { cx.error_spanned_by( cont.original, "#[serde(getter = \"...\")] can only be used in structs that have #[serde(remote = \"...\")]", ); } } } } /// Flattening has some restrictions we can test. fn check_flatten(cx: &Ctxt, cont: &Container) { match &cont.data { Data::Enum(variants) => { for variant in variants { for field in &variant.fields { check_flatten_field(cx, variant.style, field); } } } Data::Struct(style, fields) => { for field in fields { check_flatten_field(cx, *style, field); } } } } fn check_flatten_field(cx: &Ctxt, style: Style, field: &Field) { if !field.attrs.flatten() { return; } match style { Style::Tuple => { cx.error_spanned_by( field.original, "#[serde(flatten)] cannot be used on tuple structs", ); } Style::Newtype => { cx.error_spanned_by( field.original, "#[serde(flatten)] cannot be used on newtype structs", ); } _ => {} } } /// The `other` attribute must be used at most once and it must be the last /// variant of an enum. /// /// Inside a `variant_identifier` all variants must be unit variants. Inside a /// `field_identifier` all but possibly one variant must be unit variants. The /// last variant may be a newtype variant which is an implicit "other" case. fn check_identifier(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, Data::Struct(_, _) => { return; } }; for (i, variant) in variants.iter().enumerate() { match ( variant.style, cont.attrs.identifier(), variant.attrs.other(), cont.attrs.tag(), ) { // The `other` attribute may not be used in a variant_identifier. (_, Identifier::Variant, true, _) => { cx.error_spanned_by( variant.original, "#[serde(other)] may not be used on a variant identifier", ); } // Variant with `other` attribute cannot appear in untagged enum (_, Identifier::No, true, &TagType::None) => { cx.error_spanned_by( variant.original, "#[serde(other)] cannot appear on untagged enum", ); } // Variant with `other` attribute must be the last one. (Style::Unit, Identifier::Field, true, _) | (Style::Unit, Identifier::No, true, _) => { if i < variants.len() - 1 { cx.error_spanned_by( variant.original, "#[serde(other)] must be on the last variant", ); } } // Variant with `other` attribute must be a unit variant. (_, Identifier::Field, true, _) | (_, Identifier::No, true, _) => { cx.error_spanned_by( variant.original, "#[serde(other)] must be on a unit variant", ); } // Any sort of variant is allowed if this is not an identifier. (_, Identifier::No, false, _) => {} // Unit variant without `other` attribute is always fine. (Style::Unit, _, false, _) => {} // The last field is allowed to be a newtype catch-all. (Style::Newtype, Identifier::Field, false, _) => { if i < variants.len() - 1 { cx.error_spanned_by( variant.original, format!("`{}` must be the last variant", variant.ident), ); } } (_, Identifier::Field, false, _) => { cx.error_spanned_by( variant.original, "#[serde(field_identifier)] may only contain unit variants", ); } (_, Identifier::Variant, false, _) => { cx.error_spanned_by( variant.original, "#[serde(variant_identifier)] may only contain unit variants", ); } } } } /// Skip-(de)serializing attributes are not allowed on variants marked /// (de)serialize_with. fn check_variant_skip_attrs(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, Data::Struct(_, _) => { return; } }; for variant in variants.iter() { if variant.attrs.serialize_with().is_some() { if variant.attrs.skip_serializing() { cx.error_spanned_by( variant.original, format!( "variant `{}` cannot have both #[serde(serialize_with)] and #[serde(skip_serializing)]", variant.ident ), ); } for field in &variant.fields { let member = member_message(&field.member); if field.attrs.skip_serializing() { cx.error_spanned_by( variant.original, format!( "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing)]", variant.ident, member ), ); } if field.attrs.skip_serializing_if().is_some() { cx.error_spanned_by( variant.original, format!( "variant `{}` cannot have both #[serde(serialize_with)] and a field {} marked with #[serde(skip_serializing_if)]", variant.ident, member ), ); } } } if variant.attrs.deserialize_with().is_some() { if variant.attrs.skip_deserializing() { cx.error_spanned_by( variant.original, format!( "variant `{}` cannot have both #[serde(deserialize_with)] and #[serde(skip_deserializing)]", variant.ident ), ); } for field in &variant.fields { if field.attrs.skip_deserializing() { let member = member_message(&field.member); cx.error_spanned_by( variant.original, format!( "variant `{}` cannot have both #[serde(deserialize_with)] and a field {} marked with #[serde(skip_deserializing)]", variant.ident, member ), ); } } } } } /// The tag of an internally-tagged struct variant must not be /// the same as either one of its fields, as this would result in /// duplicate keys in the serialized output and/or ambiguity in /// the to-be-deserialized input. fn check_internal_tag_field_name_conflict(cx: &Ctxt, cont: &Container) { let variants = match &cont.data { Data::Enum(variants) => variants, Data::Struct(_, _) => return, }; let tag = match cont.attrs.tag() { TagType::Internal { tag } => tag.as_str(), TagType::External | TagType::Adjacent { .. } | TagType::None => return, }; let diagnose_conflict = || { cx.error_spanned_by( cont.original, format!("variant field name `{}` conflicts with internal tag", tag), ) }; for variant in variants { match variant.style { Style::Struct => { for field in &variant.fields { let check_ser = !field.attrs.skip_serializing(); let check_de = !field.attrs.skip_deserializing(); let name = field.attrs.name(); let ser_name = name.serialize_name(); if check_ser && ser_name == tag { diagnose_conflict(); return; } for de_name in field.attrs.aliases() { if check_de && de_name == tag { diagnose_conflict(); return; } } } } Style::Unit | Style::Newtype | Style::Tuple => {} } } } /// In the case of adjacently-tagged enums, the type and the /// contents tag must differ, for the same reason. fn check_adjacent_tag_conflict(cx: &Ctxt, cont: &Container) { let (type_tag, content_tag) = match cont.attrs.tag() { TagType::Adjacent { tag, content } => (tag, content), TagType::Internal { .. } | TagType::External | TagType::None => return, }; if type_tag == content_tag { cx.error_spanned_by( cont.original, format!( "enum tags `{}` for type and content conflict with each other", type_tag ), ); } } /// Enums and unit structs cannot be transparent. fn check_transparent(cx: &Ctxt, cont: &mut Container, derive: Derive) { if !cont.attrs.transparent() { return; } if cont.attrs.type_from().is_some() { cx.error_spanned_by( cont.original, "#[serde(transparent)] is not allowed with #[serde(from = \"...\")]", ); } if cont.attrs.type_try_from().is_some() { cx.error_spanned_by( cont.original, "#[serde(transparent)] is not allowed with #[serde(try_from = \"...\")]", ); } if cont.attrs.type_into().is_some() { cx.error_spanned_by( cont.original, "#[serde(transparent)] is not allowed with #[serde(into = \"...\")]", ); } let fields = match &mut cont.data { Data::Enum(_) => { cx.error_spanned_by( cont.original, "#[serde(transparent)] is not allowed on an enum", ); return; } Data::Struct(Style::Unit, _) => { cx.error_spanned_by( cont.original, "#[serde(transparent)] is not allowed on a unit struct", ); return; } Data::Struct(_, fields) => fields, }; let mut transparent_field = None; for field in fields { if allow_transparent(field, derive) { if transparent_field.is_some() { cx.error_spanned_by( cont.original, "#[serde(transparent)] requires struct to have at most one transparent field", ); return; } transparent_field = Some(field); } } match transparent_field { Some(transparent_field) => transparent_field.attrs.mark_transparent(), None => match derive { Derive::Serialize => { cx.error_spanned_by( cont.original, "#[serde(transparent)] requires at least one field that is not skipped", ); } Derive::Deserialize => { cx.error_spanned_by( cont.original, "#[serde(transparent)] requires at least one field that is neither skipped nor has a default", ); } }, } } fn member_message(member: &Member) -> String { match member { Member::Named(ident) => format!("`{}`", ident), Member::Unnamed(i) => format!("#{}", i.index), } } fn allow_transparent(field: &Field, derive: Derive) -> bool { if let Type::Path(ty) = ungroup(&field.ty) { if let Some(seg) = ty.path.segments.last() { if seg.ident == "PhantomData" { return false; } } } match derive { Derive::Serialize => !field.attrs.skip_serializing(), Derive::Deserialize => !field.attrs.skip_deserializing() && field.attrs.default().is_none(), } } fn check_from_and_try_from(cx: &Ctxt, cont: &mut Container) { if cont.attrs.type_from().is_some() && cont.attrs.type_try_from().is_some() { cx.error_spanned_by( cont.original, "#[serde(from = \"...\")] and #[serde(try_from = \"...\")] conflict with each other", ); } } serde_derive_internals-0.26.0/src/ctxt.rs000064400000000000000000000035430000000000000165310ustar 00000000000000use quote::ToTokens; use std::cell::RefCell; use std::fmt::Display; use std::thread; use syn; /// A type to collect errors together and format them. /// /// Dropping this object will cause a panic. It must be consumed using `check`. /// /// References can be shared since this type uses run-time exclusive mut checking. #[derive(Default)] pub struct Ctxt { // The contents will be set to `None` during checking. This is so that checking can be // enforced. errors: RefCell>>, } impl Ctxt { /// Create a new context object. /// /// This object contains no errors, but will still trigger a panic if it is not `check`ed. pub fn new() -> Self { Ctxt { errors: RefCell::new(Some(Vec::new())), } } /// Add an error to the context object with a tokenenizable object. /// /// The object is used for spanning in error messages. pub fn error_spanned_by(&self, obj: A, msg: T) { self.errors .borrow_mut() .as_mut() .unwrap() // Curb monomorphization from generating too many identical methods. .push(syn::Error::new_spanned(obj.into_token_stream(), msg)); } /// Add one of Syn's parse errors. pub fn syn_error(&self, err: syn::Error) { self.errors.borrow_mut().as_mut().unwrap().push(err); } /// Consume this object, producing a formatted error string if there are errors. pub fn check(self) -> Result<(), Vec> { let errors = self.errors.borrow_mut().take().unwrap(); match errors.len() { 0 => Ok(()), _ => Err(errors), } } } impl Drop for Ctxt { fn drop(&mut self) { if !thread::panicking() && self.errors.borrow().is_some() { panic!("forgot to check for errors"); } } } serde_derive_internals-0.26.0/src/mod.rs000064400000000000000000000005760000000000000163310ustar 00000000000000pub mod ast; pub mod attr; mod ctxt; pub use self::ctxt::Ctxt; mod receiver; pub use self::receiver::replace_receiver; mod case; mod check; mod respan; mod symbol; use syn::Type; #[derive(Copy, Clone)] pub enum Derive { Serialize, Deserialize, } pub fn ungroup(mut ty: &Type) -> &Type { while let Type::Group(group) = ty { ty = &group.elem; } ty } serde_derive_internals-0.26.0/src/receiver.rs000064400000000000000000000235760000000000000173630ustar 00000000000000use internals::respan::respan; use proc_macro2::Span; use quote::ToTokens; use std::mem; use syn::punctuated::Punctuated; use syn::{ parse_quote, Data, DeriveInput, Expr, ExprPath, GenericArgument, GenericParam, Generics, Macro, Path, PathArguments, QSelf, ReturnType, Type, TypeParamBound, TypePath, WherePredicate, }; pub fn replace_receiver(input: &mut DeriveInput) { let self_ty = { let ident = &input.ident; let ty_generics = input.generics.split_for_impl().1; parse_quote!(#ident #ty_generics) }; let mut visitor = ReplaceReceiver(&self_ty); visitor.visit_generics_mut(&mut input.generics); visitor.visit_data_mut(&mut input.data); } struct ReplaceReceiver<'a>(&'a TypePath); impl ReplaceReceiver<'_> { fn self_ty(&self, span: Span) -> TypePath { let tokens = self.0.to_token_stream(); let respanned = respan(tokens, span); syn::parse2(respanned).unwrap() } fn self_to_qself(&self, qself: &mut Option, path: &mut Path) { if path.leading_colon.is_some() || path.segments[0].ident != "Self" { return; } if path.segments.len() == 1 { self.self_to_expr_path(path); return; } let span = path.segments[0].ident.span(); *qself = Some(QSelf { lt_token: Token![<](span), ty: Box::new(Type::Path(self.self_ty(span))), position: 0, as_token: None, gt_token: Token![>](span), }); path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap()); let segments = mem::replace(&mut path.segments, Punctuated::new()); path.segments = segments.into_pairs().skip(1).collect(); } fn self_to_expr_path(&self, path: &mut Path) { let self_ty = self.self_ty(path.segments[0].ident.span()); let variant = mem::replace(path, self_ty.path); for segment in &mut path.segments { if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments { if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() { bracketed.colon2_token = Some(::default()); } } } if variant.segments.len() > 1 { path.segments.push_punct(::default()); path.segments.extend(variant.segments.into_pairs().skip(1)); } } } impl ReplaceReceiver<'_> { // `Self` -> `Receiver` fn visit_type_mut(&mut self, ty: &mut Type) { let span = if let Type::Path(node) = ty { if node.qself.is_none() && node.path.is_ident("Self") { node.path.segments[0].ident.span() } else { self.visit_type_path_mut(node); return; } } else { self.visit_type_mut_impl(ty); return; }; *ty = self.self_ty(span).into(); } // `Self::Assoc` -> `::Assoc` fn visit_type_path_mut(&mut self, ty: &mut TypePath) { if ty.qself.is_none() { self.self_to_qself(&mut ty.qself, &mut ty.path); } self.visit_type_path_mut_impl(ty); } // `Self::method` -> `::method` fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) { if expr.qself.is_none() { self.self_to_qself(&mut expr.qself, &mut expr.path); } self.visit_expr_path_mut_impl(expr); } // Everything below is simply traversing the syntax tree. fn visit_type_mut_impl(&mut self, ty: &mut Type) { match ty { Type::Array(ty) => { self.visit_type_mut(&mut ty.elem); self.visit_expr_mut(&mut ty.len); } Type::BareFn(ty) => { for arg in &mut ty.inputs { self.visit_type_mut(&mut arg.ty); } self.visit_return_type_mut(&mut ty.output); } Type::Group(ty) => self.visit_type_mut(&mut ty.elem), Type::ImplTrait(ty) => { for bound in &mut ty.bounds { self.visit_type_param_bound_mut(bound); } } Type::Macro(ty) => self.visit_macro_mut(&mut ty.mac), Type::Paren(ty) => self.visit_type_mut(&mut ty.elem), Type::Path(ty) => { if let Some(qself) = &mut ty.qself { self.visit_type_mut(&mut qself.ty); } self.visit_path_mut(&mut ty.path); } Type::Ptr(ty) => self.visit_type_mut(&mut ty.elem), Type::Reference(ty) => self.visit_type_mut(&mut ty.elem), Type::Slice(ty) => self.visit_type_mut(&mut ty.elem), Type::TraitObject(ty) => { for bound in &mut ty.bounds { self.visit_type_param_bound_mut(bound); } } Type::Tuple(ty) => { for elem in &mut ty.elems { self.visit_type_mut(elem); } } Type::Infer(_) | Type::Never(_) | Type::Verbatim(_) => {} #[cfg(test)] Type::__TestExhaustive(_) => unimplemented!(), #[cfg(not(test))] _ => {} } } fn visit_type_path_mut_impl(&mut self, ty: &mut TypePath) { if let Some(qself) = &mut ty.qself { self.visit_type_mut(&mut qself.ty); } self.visit_path_mut(&mut ty.path); } fn visit_expr_path_mut_impl(&mut self, expr: &mut ExprPath) { if let Some(qself) = &mut expr.qself { self.visit_type_mut(&mut qself.ty); } self.visit_path_mut(&mut expr.path); } fn visit_path_mut(&mut self, path: &mut Path) { for segment in &mut path.segments { self.visit_path_arguments_mut(&mut segment.arguments); } } fn visit_path_arguments_mut(&mut self, arguments: &mut PathArguments) { match arguments { PathArguments::None => {} PathArguments::AngleBracketed(arguments) => { for arg in &mut arguments.args { match arg { GenericArgument::Type(arg) => self.visit_type_mut(arg), GenericArgument::Binding(arg) => self.visit_type_mut(&mut arg.ty), GenericArgument::Lifetime(_) | GenericArgument::Constraint(_) | GenericArgument::Const(_) => {} } } } PathArguments::Parenthesized(arguments) => { for argument in &mut arguments.inputs { self.visit_type_mut(argument); } self.visit_return_type_mut(&mut arguments.output); } } } fn visit_return_type_mut(&mut self, return_type: &mut ReturnType) { match return_type { ReturnType::Default => {} ReturnType::Type(_, output) => self.visit_type_mut(output), } } fn visit_type_param_bound_mut(&mut self, bound: &mut TypeParamBound) { match bound { TypeParamBound::Trait(bound) => self.visit_path_mut(&mut bound.path), TypeParamBound::Lifetime(_) => {} } } fn visit_generics_mut(&mut self, generics: &mut Generics) { for param in &mut generics.params { match param { GenericParam::Type(param) => { for bound in &mut param.bounds { self.visit_type_param_bound_mut(bound); } } GenericParam::Lifetime(_) | GenericParam::Const(_) => {} } } if let Some(where_clause) = &mut generics.where_clause { for predicate in &mut where_clause.predicates { match predicate { WherePredicate::Type(predicate) => { self.visit_type_mut(&mut predicate.bounded_ty); for bound in &mut predicate.bounds { self.visit_type_param_bound_mut(bound); } } WherePredicate::Lifetime(_) | WherePredicate::Eq(_) => {} } } } } fn visit_data_mut(&mut self, data: &mut Data) { match data { Data::Struct(data) => { for field in &mut data.fields { self.visit_type_mut(&mut field.ty); } } Data::Enum(data) => { for variant in &mut data.variants { for field in &mut variant.fields { self.visit_type_mut(&mut field.ty); } } } Data::Union(_) => {} } } fn visit_expr_mut(&mut self, expr: &mut Expr) { match expr { Expr::Binary(expr) => { self.visit_expr_mut(&mut expr.left); self.visit_expr_mut(&mut expr.right); } Expr::Call(expr) => { self.visit_expr_mut(&mut expr.func); for arg in &mut expr.args { self.visit_expr_mut(arg); } } Expr::Cast(expr) => { self.visit_expr_mut(&mut expr.expr); self.visit_type_mut(&mut expr.ty); } Expr::Field(expr) => self.visit_expr_mut(&mut expr.base), Expr::Index(expr) => { self.visit_expr_mut(&mut expr.expr); self.visit_expr_mut(&mut expr.index); } Expr::Paren(expr) => self.visit_expr_mut(&mut expr.expr), Expr::Path(expr) => self.visit_expr_path_mut(expr), Expr::Unary(expr) => self.visit_expr_mut(&mut expr.expr), _ => {} } } fn visit_macro_mut(&mut self, _mac: &mut Macro) {} } serde_derive_internals-0.26.0/src/respan.rs000064400000000000000000000007030000000000000170320ustar 00000000000000use proc_macro2::{Group, Span, TokenStream, TokenTree}; pub(crate) fn respan(stream: TokenStream, span: Span) -> TokenStream { stream .into_iter() .map(|token| respan_token(token, span)) .collect() } fn respan_token(mut token: TokenTree, span: Span) -> TokenTree { if let TokenTree::Group(g) = &mut token { *g = Group::new(g.delimiter(), respan(g.stream(), span)); } token.set_span(span); token } serde_derive_internals-0.26.0/src/symbol.rs000064400000000000000000000044620000000000000170550ustar 00000000000000use std::fmt::{self, Display}; use syn::{Ident, Path}; #[derive(Copy, Clone)] pub struct Symbol(&'static str); pub const ALIAS: Symbol = Symbol("alias"); pub const BORROW: Symbol = Symbol("borrow"); pub const BOUND: Symbol = Symbol("bound"); pub const CONTENT: Symbol = Symbol("content"); pub const CRATE: Symbol = Symbol("crate"); pub const DEFAULT: Symbol = Symbol("default"); pub const DENY_UNKNOWN_FIELDS: Symbol = Symbol("deny_unknown_fields"); pub const DESERIALIZE: Symbol = Symbol("deserialize"); pub const DESERIALIZE_WITH: Symbol = Symbol("deserialize_with"); pub const FIELD_IDENTIFIER: Symbol = Symbol("field_identifier"); pub const FLATTEN: Symbol = Symbol("flatten"); pub const FROM: Symbol = Symbol("from"); pub const GETTER: Symbol = Symbol("getter"); pub const INTO: Symbol = Symbol("into"); pub const OTHER: Symbol = Symbol("other"); pub const REMOTE: Symbol = Symbol("remote"); pub const RENAME: Symbol = Symbol("rename"); pub const RENAME_ALL: Symbol = Symbol("rename_all"); pub const SERDE: Symbol = Symbol("serde"); pub const SERIALIZE: Symbol = Symbol("serialize"); pub const SERIALIZE_WITH: Symbol = Symbol("serialize_with"); pub const SKIP: Symbol = Symbol("skip"); pub const SKIP_DESERIALIZING: Symbol = Symbol("skip_deserializing"); pub const SKIP_SERIALIZING: Symbol = Symbol("skip_serializing"); pub const SKIP_SERIALIZING_IF: Symbol = Symbol("skip_serializing_if"); pub const TAG: Symbol = Symbol("tag"); pub const TRANSPARENT: Symbol = Symbol("transparent"); pub const TRY_FROM: Symbol = Symbol("try_from"); pub const UNTAGGED: Symbol = Symbol("untagged"); pub const VARIANT_IDENTIFIER: Symbol = Symbol("variant_identifier"); pub const WITH: Symbol = Symbol("with"); pub const EXPECTING: Symbol = Symbol("expecting"); impl PartialEq for Ident { fn eq(&self, word: &Symbol) -> bool { self == word.0 } } impl<'a> PartialEq for &'a Ident { fn eq(&self, word: &Symbol) -> bool { *self == word.0 } } impl PartialEq for Path { fn eq(&self, word: &Symbol) -> bool { self.is_ident(word.0) } } impl<'a> PartialEq for &'a Path { fn eq(&self, word: &Symbol) -> bool { self.is_ident(word.0) } } impl Display for Symbol { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str(self.0) } }