### Struct with Optional Fields and Merge Functionality Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=std%3A%3Avec Demonstrates how to use the `optfield` macro to create an optional field struct and merge an instance of it into an existing struct. The example shows how the `text` field is updated while the `number` field remains unchanged. ```Rust use optfield::optfield; #[derive(Debug, PartialEq)] struct Opt { text: Option, number: Option, } impl Opt { fn merge_opt(&mut self, other: Opt) { if let Some(text) = other.text { self.text = Some(text); } if let Some(number) = other.number { self.number = Some(number); } } } let mut original = Opt { text: "awesome".to_string(), number: 1 }; let opt = Opt { text: Some("amazing".to_string()), number: None }; original.merge_opt(opt); // text field value is merged assert_eq!(original.text, "amazing"); // number field stays the same assert_eq!(original.number, 1); ``` -------------------------------- ### Merging Optional Fields with `optfield` Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates how to merge an `Opt` struct into an existing struct using the `merge_opt` method generated by the `optfield` macro. The example shows how optional fields in `Opt` can update corresponding fields in the original struct. ```rust # use optfield::optfield; #[optfield(Opt)] struct Original { text: String, number: i32, } impl Original { fn merge_opt(&mut self, opt: Opt) { if let Some(text) = opt.text { self.text = text; } if let Some(number) = opt.number { self.number = number; } } } let mut original = Original { text: "awesome".to_string(), number: 1 }; let opt = Opt { text: Some("amazing".to_string()), number: None }; original.merge_opt(opt); // text field value is merged assert_eq!(original.text, "amazing"); // number field stays the same assert_eq!(original.number, 1); ``` -------------------------------- ### Default Field Attribute Handling Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search=std%3A%3Avec By default, no field attributes are inserted when using `attrs`. This example demonstrates the default behavior where only the derive attribute is kept. ```rust #[optfield(Opt, attrs)] #[derive(Deserialize)] struct MyStruct { #[serde(rename = "text")] my_text: String } ``` ```rust #[derive(Deserialize)] struct Opt { my_text: Option } ``` -------------------------------- ### Initialize Args struct Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool Creates a new Args struct with default values, setting the item field. ```rust impl Args { fn new(item: GenItem) -> Self { Self { item, merge: None, rewrap: false, doc: None, attrs: None, field_doc: false, field_attrs: None, from: false, } } } ``` -------------------------------- ### Implementing From for Opt with optfield Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Shows how to use the `from` argument in the `optfield` macro to automatically implement the `From` trait for the generated `Opt` struct, allowing easy conversion. ```rust # use optfield::*; #[optfield(Opt, from)] struct MyStruct { text: String, number: i32, } let original = MyStruct { text: "super".to_string(), number: 2, }; let from = Opt::from(original); assert_eq!(from.text.unwrap(), "super"); assert_eq!(from.number.unwrap(), 2); ``` -------------------------------- ### Optional Struct with Existing Option Fields Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=std%3A%3Avec By default, fields already wrapped in Option are not rewrapped. This example shows a struct with a mix of Option and non-Option fields. ```rust # use optfield::*; #[optfield(Opt)] struct MyStruct { text: Option, number: i32 } ``` -------------------------------- ### Replacing All Field Attributes Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search=std%3A%3Avec Use `field_attrs = (...)` to replace all existing field attributes with a new set. This is useful for a complete override, for example, to ensure all fields have a default value. ```rust #[optfield( Opt, attrs, field_attrs = ( serde(default) ) )] #[derive(Deserialize)] struct MyStruct { #[serde(rename = "text")] my_text: String, #[serde(rename = "number")] my_number: i32 } ``` ```rust #[derive(Deserialize)] struct Opt { #[serde(default)] my_text: Option, #[serde(default)] my_number: Option } ``` -------------------------------- ### Creating Opt Struct from Original Struct using From Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search= Demonstrates how to create an Opt struct from an original struct using the implemented `From` trait. ```rust let original = MyStruct { text: "super".to_string(), number: 2, }; let from = Opt::from(original); assert_eq!(from.text.unwrap(), "super"); assert_eq!(from.number.unwrap(), 2); ``` -------------------------------- ### Basic Struct Transformation Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Demonstrates the fundamental usage of the optfield macro to convert a struct with String fields into a struct with Option fields. ```rust # use optfield::*; #[optfield(Opt)] struct MyStruct { text: String } // Will generate: struct Opt { text: Option } ``` -------------------------------- ### Default Rewrapping Behavior Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search= By default, fields already wrapped in Option are not rewrapped. This example shows the default behavior where `text: Option` remains unchanged, while `number: i32` becomes `Option`. ```rust #[optfield(Opt)] struct MyStruct { text: Option, number: i32 } ``` ```rust struct Opt { text: Option, number: Option } ``` -------------------------------- ### Initialize ArgList struct Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool Creates a new ArgList struct with default values, initializing the item and other optional fields to None. ```rust impl ArgList { fn new(item: GenItem) -> Self { Self { item, merge: None, doc: None, rewrap: None, attrs: None, field_doc: None, field_attrs: None, from: None, list: Vec::with_capacity(6), } } fn next_is_kw(input: ParseStream) -> bool { input.peek(kw::doc) || input.peek(kw::merge_fn) || input.peek(kw::rewrap) || input.peek(kw::field_doc) ``` -------------------------------- ### Parse documentation string Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool Parses documentation strings for optional fields, supporting both default and custom strings. ```rust #[test] fn parse_doc() { let cases = vec![ (quote! {Opt, doc}, Doc::Same), ( quote! {Opt, doc = "custom docs"}, Doc::Custom("custom docs".to_string()), ), ]; for (args_tokens, doc) in cases { let args: Args = syn::parse2(args_tokens).unwrap(); assert_eq!(args.doc, Some(doc)); } } ``` -------------------------------- ### Rust Constructor for Args Struct Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=std%3A%3Avec Provides a constructor function `new` for the `Args` struct, initializing it with default values. ```rust impl Args { fn new(item: GenItem) -> Self { Self { item, merge: None, rewrap: false, doc: None, attrs: None, field_doc: false, field_attrs: None, from: false, } } } ``` -------------------------------- ### Implement From for Opt with optfield Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search=std%3A%3Avec Use the `from` argument to automatically implement `From` for the generated `Opt` struct. This allows easy conversion of an original struct into its optional representation. ```rust #[optfield(Opt, from)] struct MyStruct { text: String, number: i32, } let original = MyStruct { text: "super".to_string(), number: 2, }; let from = Opt::from(original); assert_eq!(from.text.unwrap(), "super"); assert_eq!(from.number.unwrap(), 2); ``` -------------------------------- ### Struct Generation with Option Fields and Clone Derive Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates generating an `Option`-wrapped struct with the `Clone` derive attribute applied. ```rust # use optfield::*; #[cfg(test)] #[derive(Clone)] struct Opt { text: Option } ``` -------------------------------- ### Duplicating Documentation with `doc` Argument Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search= To document the generated opt struct, use the `doc` argument by itself to duplicate the documentation from the original struct. This is useful for maintaining consistent documentation. ```rust /// My struct documentation /// ... #[optfield(Opt, doc)] struct MyStruct { text: String } ``` ```rust /// My struct documentation /// ... struct Opt { text: Option } ``` -------------------------------- ### Custom Documentation with `doc` Value Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search= Provide custom documentation for the generated opt struct by assigning a string value to the `doc` argument. This allows for tailored documentation specific to the optional version of the struct. ```rust #[optfield( Opt, doc = " Custom documentation for Opt struct... " )] struct MyStruct { text: String } ``` ```rust /// Custom documentation /// for Opt struct... struct Opt { text: Option } ``` -------------------------------- ### Adding Attributes with OptionField Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates adding new attributes to an item while keeping existing ones using the `optfield` macro with 'Opt', 'attrs', and the 'add' function. ```Rust let (item, args) = parse_item_and_args( quote! { #[some] #[attrs] struct S; }, quote! { Opt, attrs = add( other attributes ) }, ); let new_attrs = parse_attrs(quote! { #[other] #[attributes] }); let generated = generate(&item, &args); assert!(attrs_contain_all(&generated, &item.attrs)); assert!(attrs_contain_all(&generated, &new_attrs)); ``` -------------------------------- ### Replacing Attributes with OptionField Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Illustrates replacing existing attributes with new ones using the `optfield` macro, specifying 'Opt', 'attrs', and a replacement tuple. ```Rust let (item, args) = parse_item_and_args( quote! { #[some] #[attrs] struct S; }, quote! { Opt, attrs = ( other attributes ) }, ); let new_attrs = parse_attrs(quote! { #[other] #[attributes] }); let generated = generate(&item, &args); assert!(!attrs_contain_any(&generated, &item.attrs)); assert!(attrs_contain_all(&generated, &new_attrs)); ``` -------------------------------- ### Duplicating Documentation Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Shows how to use the 'doc' argument to copy documentation from the original struct to the generated optional struct. The generated struct will have the same doc comments. ```rust # use optfield::*; /// My struct documentation /// ... #[optfield(Opt, doc)] struct MyStruct { text: String } ``` ```rust /// My struct documentation /// ... struct Opt { text: Option } ``` -------------------------------- ### Keyword definitions for optfield arguments Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html Defines custom keywords used for parsing arguments in the optfield crate. ```rust mod kw { // NOTE: when adding new keywords update ArgList::next_is_kw syn::custom_keyword!(doc); syn::custom_keyword!(merge_fn); syn::custom_keyword!(rewrap); syn::custom_keyword!(attrs); syn::custom_keyword!(field_doc); syn::custom_keyword!(field_attrs); syn::custom_keyword!(from); pub mod attrs_sub { syn::custom_keyword!(add); } } ``` -------------------------------- ### Replace Attributes with OptField Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html Demonstrates replacing existing attributes with new ones using OptField. ```rust #[test] fn replace_attrs() { let (item, args) = parse_item_and_args( quote! { #[some] #[attrs] struct S; }, quote! { Opt, attrs = ( other attributes ) }, ); let new_attrs = parse_attrs(quote! { #[other] #[attributes] }); let generated = generate(&item, &args); assert!(!attrs_contain_any(&generated, &item.attrs)); assert!(attrs_contain_all(&generated, &new_attrs)); } ``` -------------------------------- ### Add Custom Documentation to Generated Struct with optfield Macro Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search= Provide custom documentation for the generated struct by assigning a string literal to the `doc` argument. ```rust # use optfield::*; #[optfield( Opt, doc = " Custom documentation for Opt struct... " )] struct MyStruct { text: String } ``` -------------------------------- ### Parsing arguments for optfield Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E This snippet shows the parsing logic for arguments in the optfield crate, handling various keywords and their associated values. ```Rust use proc_macro2::{Group, Span}; use syn::parse::{Error, Parse, ParseStream, Result}; use syn::token::{Comma, Eq, Pub}; use syn::{parse2, Ident, LitStr, Meta, Visibility}; mod kw { // NOTE: when adding new keywords update ArgList::next_is_kw syn::custom_keyword!(doc); syn::custom_keyword!(merge_fn); syn::custom_keyword!(rewrap); syn::custom_keyword!(attrs); syn::custom_keyword!(field_doc); syn::custom_keyword!(field_attrs); syn::custom_keyword!(from); pub mod attrs_sub { syn::custom_keyword!(add); } } #[cfg_attr(test, derive(PartialEq))] pub struct Args { pub item: GenItem, pub merge: Option, pub rewrap: bool, pub doc: Option, pub attrs: Option, pub field_doc: bool, pub field_attrs: Option, pub from: bool, } enum Arg { Merge(MergeFn), Doc(Doc), Rewrap(bool), Attrs(Attrs), FieldDocs(bool), FieldAttrs(Attrs), From(bool), } #[cfg_attr(test, derive(PartialEq))] pub struct GenItem { pub name: Ident, pub visibility: Option, } #[cfg_attr(test, derive(Clone, Debug, PartialEq))] pub struct MergeFn { pub visibility: Visibility, pub name: MergeFnName, } #[cfg_attr(test, derive(Clone, Debug, PartialEq))] pub enum MergeFnName { Default, Custom(Ident), } #[cfg_attr(test, derive(Debug, PartialEq))] pub enum Doc { Same, Custom(String), } #[cfg_attr(test, derive(Debug, PartialEq))] pub enum Attrs { /// Keep same attributes. Keep, /// Replace with given attributes. Replace(Vec), /// Keep original attributes and add the given ones. Add(Vec), } #[derive(Debug)] pub struct AttrList(Vec); /// Parser for unordered args. struct ArgList { item: GenItem, merge: Option, doc: Option, rewrap: Option, attrs: Option, field_doc: Option, field_attrs: Option, from: Option, list: Vec, } impl Parse for Args { fn parse(input: ParseStream) -> Result { let arg_list: ArgList = input.parse()?; Ok(arg_list.into()) } } impl Parse for ArgList { fn parse(input: ParseStream) -> Result { if input.is_empty() { return Err(input.error("expected opt struct name")); } if ArgList::next_is_kw(input) { return Err(input.error("first argument must be opt struct name")); } let item = input.parse()?; let mut arg_list = ArgList::new(item); while !input.is_empty() { input.parse::()?; // allow trailing commas if input.is_empty() { break; } let lookahead = input.lookahead1(); if lookahead.peek(kw::doc) { arg_list.parse_doc(input)?; } else if lookahead.peek(kw::merge_fn) { arg_list.parse_merge(input)?; } else if lookahead.peek(kw::rewrap) { arg_list.parse_rewrap(input)?; } else if lookahead.peek(kw::attrs) { arg_list.parse_attrs(input)?; } else if lookahead.peek(kw::field_doc) { arg_list.parse_field_doc(input)?; } else if lookahead.peek(kw::field_attrs) { arg_list.parse_field_attrs(input)?; } else if lookahead.peek(kw::from) { arg_list.parse_from(input)?; } else { return Err(lookahead.error()); } } Ok(arg_list) } } impl Args { fn new(item: GenItem) -> Self { Self { item, merge: None, rewrap: false, doc: None, attrs: None, field_doc: false, field_attrs: None, from: false, } } } impl ArgList { fn new(item: GenItem) -> Self { Self { item, merge: None, doc: None, rewrap: None, attrs: None, field_doc: None, field_attrs: None, from: None, list: Vec::with_capacity(6), } } fn next_is_kw(input: ParseStream) -> bool { input.peek(kw::doc) || input.peek(kw::merge_fn) || input.peek(kw::rewrap) || input.peek(kw::field_doc) ``` -------------------------------- ### Rust Enum for Documentation Handling Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=std%3A%3Avec Defines how documentation should be handled, either keeping it the same or replacing it with custom documentation. ```rust #[cfg_attr(test, derive(Debug, PartialEq))] pub enum Doc { Same, Custom(String), } ``` -------------------------------- ### Test Utility Functions for OptField Macro Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html A collection of utility functions used for testing the optfield macro. These functions help in parsing tokens, fields, arguments, and attributes, as well as comparing attributes. ```rust use proc_macro2::TokenStream; use syn::{parse::Parser, parse2, Attribute, Field, Fields, ItemStruct, Type, Visibility}; use crate::args::Args; use crate::attrs::generator::is_doc_attr; pub fn parse_item_and_args( item_tokens: TokenStream, args_tokens: TokenStream, ) -> (ItemStruct, Args) { (parse_item(item_tokens), parse_args(args_tokens)) } pub fn parse_field_and_args( field_tokens: TokenStream, args_tokens: TokenStream, ) -> (Field, Args) { (parse_field(field_tokens), parse_args(args_tokens)) } pub fn parse_item(tokens: TokenStream) -> ItemStruct { parse2(tokens).unwrap() } pub fn parse_field(tokens: TokenStream) -> Field { Field::parse_named.parse2(tokens).unwrap() } pub fn parse_args(tokens: TokenStream) -> Args { parse2(tokens).unwrap() } pub fn parse_attr(tokens: TokenStream) -> Attribute { parse_attrs(tokens).get(0).unwrap().clone() } pub fn parse_attrs(tokens: TokenStream) -> Vec { Attribute::parse_outer.parse2(tokens).unwrap() } pub fn parse_type(tokens: TokenStream) -> Type { parse2(tokens).unwrap() } pub fn parse_types(tokens: Vec) -> Vec { tokens.into_iter().map(parse_type).collect() } pub fn field_types(fields: Fields) -> Vec { fields.iter().map(|f| f.ty.clone()).collect() } pub fn parse_visibility(tokens: TokenStream) -> Visibility { parse2(tokens).unwrap() } pub fn attrs_contain_all(attrs: &[Attribute], other_attrs: &[Attribute]) -> bool { for attr in other_attrs { if !attrs.contains(attr) { return false; } } true } pub fn attrs_contain_any(attrs: &[Attribute], any_attrs: &[Attribute]) -> bool { for attr in any_attrs { if attrs.contains(attr) { return true; } } false } pub fn doc_attrs(attrs: &[Attribute]) -> Vec { attrs .iter() .filter(|a| is_doc_attr(a)) .map(|a| a.clone()) .collect() } ``` -------------------------------- ### Args struct definition Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html Defines the main `Args` struct which holds all parsed arguments for optfield. ```rust #[cfg_attr(test, derive(PartialEq))] pub struct Args { pub item: GenItem, pub merge: Option, pub rewrap: bool, pub doc: Option, pub attrs: Option, pub field_doc: bool, pub field_attrs: Option, pub from: bool, } ``` -------------------------------- ### Adding Attributes to Fields Source: https://docs.rs/optfield/0.4.0/src/optfield/fields/attrs.rs.html Demonstrates parsing a field with existing attributes and additional arguments, then generating code and asserting that the generated attributes contain all expected attributes. ```rust fn add_attrs() { let (field, args) = parse_field_and_args( quote! { #[old] #[attrs] field: u8 }, quote! { Opt, field_attrs = add( new, field, attributes ) }, ); let new_attrs = parse_attrs(quote! { #[new] #[field] #[attributes] }); let generated = generate(&field, &args); assert!(attrs_contain_all(&generated, &field.attrs)); assert!(attrs_contain_all(&generated, &new_attrs)); } ``` -------------------------------- ### Parse Args from Stream Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool Parses a stream of tokens into the Args struct, which represents the configuration options for optfield. ```rust impl Parse for Args { fn parse(input: ParseStream) -> Result { let arg_list: ArgList = input.parse()?; Ok(arg_list.into()) } } ``` -------------------------------- ### Public Generate Function Source: https://docs.rs/optfield/0.4.0/src/optfield/fields/attrs.rs.html The main entry point for generating attributes for a given field and arguments. ```Rust pub fn generate(field: &Field, args: &Args) -> Vec { FieldAttrGen::new(field, args).generate() } ``` -------------------------------- ### Struct Transformation with Merge Functionality Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Shows how to use the `merge_fn` argument with the optfield macro to add a method for merging an optional struct back into the original. ```rust # use optfield::*; #[optfield(Opt, merge_fn)] struct MyStruct { text: String, number: i32 } let mut original = MyStruct { text: "hello".to_string(), number: 123 }; // The generated `Opt` struct would have a `merge_opt` method. ``` -------------------------------- ### Attribute Order Awareness Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search= Demonstrates that optfield is unaware of attributes defined before it. ```rust # use optfield::*; #[cfg(test)] // optfield is unaware of this attribute #[optfield(Opt, attrs)] #[derive(Debug)] struct MyStruct; ``` ```rust # #[derive(Debug)] struct Opt; ``` -------------------------------- ### Custom Documentation Generation Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Generates custom documentation attributes for a struct based on provided arguments. This is useful when you need to dynamically set documentation strings. ```Rust use quote::quote; use syn::{parse2, Attribute, ItemStruct, Meta}; use crate::args::{Args, Attrs, Doc}; use crate::error::unexpected; pub mod generator; use generator::AttrGenerator; struct AttrGen<'a> { item: &'a ItemStruct, args: &'a Args, } impl<'a> AttrGen<'a> { fn new(item: &'a ItemStruct, args: &'a Args) -> Self { Self { item, args } } } impl AttrGenerator for AttrGen<'_> { fn no_docs(&self) -> bool { self.args.doc.is_none() } fn error_action_text(&self) -> String { format!("generating {} attrs", self.item.ident) } fn original_attrs(&self) -> &[Attribute] { &self.item.attrs } fn attrs_arg(&self) -> &Option { &self.args.attrs } fn custom_docs(&self) -> Option { if let Some(Doc::Custom(d)) = &self.args.doc { let tokens = quote! { doc = #d }; Some( parse2(tokens) .unwrap_or_else(|e| panic!("{}", unexpected(self.error_action_text(), e))), ) } else { None } } fn keep_original_docs(&self) -> bool { use Doc::*; match self.args.doc { None | Some(Custom(_)) => false, Some(Same) => true, } } } pub fn generate(item: &ItemStruct, args: &Args) -> Vec { AttrGen::new(item, args).generate() } ``` -------------------------------- ### Struct Definition with From Implementation Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search= Defines a struct with the `from` argument to automatically implement `From` for the corresponding Opt struct. ```rust #[optfield(Opt, from)] struct MyStruct { text: String, number: i32, } ``` -------------------------------- ### Parse Doc Comment Options Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html Parses documentation comment options, including inheriting documentation from the field or providing custom documentation strings. ```Rust let cases = vec![ (quote! {Opt, doc}, Doc::Same), ( quote! {Opt, doc = "custom docs"}, Doc::Custom("custom docs".to_string()), ), ]; for (args_tokens, doc) in cases { let args: Args = syn::parse2(args_tokens).unwrap(); assert_eq!(args.doc, Some(doc)); } ``` -------------------------------- ### Custom Visibility for Opt Struct Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Shows how to specify custom visibility (e.g., pub(crate)) for the generated optional struct. Field visibility is maintained. ```rust # use optfield::*; #[optfield(pub(crate) Opt)] struct MyStruct { text: String } ``` ```rust pub(crate) struct Opt { text: Option } ``` -------------------------------- ### Generated Optional Struct with Custom Documentation Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=std%3A%3Avec The generated struct contains the custom documentation provided through the `doc` argument. ```rust /// Custom documentation /// for Opt struct... struct Opt { text: Option } ``` -------------------------------- ### Basic Struct Generation Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html Generates an optional version of a struct. The generated struct will have fields wrapped in `Option`. ```rust #[cfg(test)] #[derive(Clone)] struct Opt { text: Option } ``` -------------------------------- ### Merging Opt Struct into Original Struct Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search= Demonstrates how to use the generated `merge_opt` method to update an original struct with values from an opt struct. ```rust let mut original = MyStruct { text: "awesome".to_string(), number: 1 }; let opt = Opt { text: Some("amazing".to_string()), number: None }; original.merge_opt(opt); // text field value is merged assert_eq!(original.text, "amazing"); // number field stays the same assert_eq!(original.number, 1); ``` -------------------------------- ### Generate Optional Field Struct with Custom Doc String Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html Using the 'doc' argument with a custom string to provide documentation for the generated opt struct. ```rust # use optfield::*; #[optfield( Opt, doc = " Custom documentation for Opt struct... " )] struct MyStruct { text: String } ``` -------------------------------- ### Basic Merge Operation with Optfield Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Demonstrates how the `merge_opt` function merges an `Opt` struct into an existing struct, updating fields that are `Some` and leaving others unchanged. ```rust # use optfield::*; #[derive(Debug, OptField)] struct MyStruct { text: String, number: u32, } let mut original = MyStruct { text: "awesome".to_string(), number: 1 }; let opt = Opt { text: Some("amazing".to_string()), number: None }; original.merge_opt(opt); // text field value is merged assert_eq!(original.text, "amazing"); // number field stays the same assert_eq!(original.number, 1); ``` -------------------------------- ### Rewrapping Option Fields Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Demonstrates how to use the 'rewrap' argument to re-wrap fields that are already Option into Option>. The 'number' field is wrapped as Option. ```rust # use optfield::*; #[optfield(Opt, rewrap)] struct MyStruct { text: Option, number: i32 } ``` ```rust struct Opt { text: Option>, number: Option } ``` -------------------------------- ### Parse Field Documentation Argument Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool Parses the `field_doc` argument. This is used when documenting optional fields. ```rust #[test] fn parse_field_doc() { let args = parse_args(quote! { Opt, field_doc }); assert!(args.field_doc); } ``` -------------------------------- ### Generate Optional Field Struct with Doc Argument Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html Using the 'doc' argument with optfield to copy documentation from the original struct to the generated opt struct. ```rust /// My struct documentation /// ... # use optfield::*; #[optfield(Opt, doc)] struct MyStruct { text: String } ``` -------------------------------- ### Test Macro for Struct Name Order Panics Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool A macro to generate tests that verify panics when the struct name is not the first argument. ```Rust macro_rules! struct_name_not_first_panics { ($attr:meta) => { paste::item! { #[test] #[should_panic(expected = "first argument must be opt struct name")] fn [<$attr _first_panics>]() { parse_args(quote! { $attr, Opt }); } } }; } ``` -------------------------------- ### Inheriting Documentation with `doc` Argument Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=std%3A%3Avec Use the `doc` argument without a value to copy documentation from the original struct to the generated optional struct. ```rust # use optfield::*; /// My struct documentation /// ... #[optfield(Opt, doc)] struct MyStruct { text: String } ``` -------------------------------- ### Rust Syn Imports for Argument Parsing Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=std%3A%3Avec Imports necessary types from the `proc_macro2` and `syn` crates for parsing arguments in Rust code. ```rust use proc_macro2::{Group, Span}; use syn::parse::{Error, Parse, ParseStream, Result}; use syn::token::{Comma, Eq, Pub}; use syn::{parse2, Ident, LitStr, Meta, Visibility}; ``` -------------------------------- ### Generate From Trait Implementation Source: https://docs.rs/optfield/0.4.0/src/optfield/from.rs.html Use this function to generate the `From` trait implementation for converting a source struct to a target struct. It conditionally generates the implementation based on the `Args.from` flag. ```rust use proc_macro2::TokenStream; use quote::{quote, ToTokens}; use syn::{Fields, Index, ItemStruct}; use crate::args::Args; use crate::fields; const CFG: &str = "cfg"; pub fn generate(item: &ItemStruct, opt_item: &ItemStruct, args: &Args) -> TokenStream { if args.from { let item_name = &item.ident; let item_generics = &item.generics; let opt_name = &opt_item.ident; let opt_generics = &opt_item.generics; let fields = field_bindings(&item.fields, args); quote! { impl#opt_generics From<#item_name#item_generics> for #opt_name#opt_generics { fn from(item: #item_name#item_generics) -> #opt_name#opt_generics { #opt_name { #fields } } } } } else { TokenStream::new() } } ``` -------------------------------- ### Add Attributes with OptField Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html Demonstrates adding new attributes to a struct while keeping existing ones using OptField. ```rust #[test] fn add_attrs() { let (item, args) = parse_item_and_args( quote! { #[some] #[attrs] struct S; }, quote! { Opt, attrs = add( other attributes ) }, ); let new_attrs = parse_attrs(quote! { #[other] #[attributes] }); let generated = generate(&item, &args); assert!(attrs_contain_all(&generated, &item.attrs)); assert!(attrs_contain_all(&generated, &new_attrs)); } ``` -------------------------------- ### Generated Optional Struct with Inherited Documentation Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=std%3A%3Avec The generated struct includes the documentation inherited from the original struct via the `doc` argument. ```rust /// My struct documentation /// ... struct Opt { text: Option } ``` -------------------------------- ### Doc enum definition Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html Represents documentation, either 'Same' or a 'Custom' string. ```rust #[cfg_attr(test, derive(Debug, PartialEq))] pub enum Doc { Same, Custom(String), } ``` -------------------------------- ### Test: keep_same_docs Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search=std%3A%3Avec Verifies that documentation attributes are preserved when the 'doc = Same' option is used. ```rust #[cfg(test)] mod tests { use super::*; use crate::test_util::*; #[test] fn keep_same_docs() { let item = parse_item(quote! { /// some /// docs #[some_attr] struct S; }); let cases = vec![ quote! { Opt, doc }, quote! { Opt, doc, attrs }, quote! { Opt, doc, attrs = (new_attr) }, quote! { Opt, doc, attrs = add(new_attr) }, ]; let item_docs = doc_attrs(&item.attrs); for case in cases { let args = parse_args(case); let generated = generate(&item, &args); assert!(attrs_contain_all(&generated, &item_docs)); } } ``` -------------------------------- ### Converting ArgList to Args Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool Converts an ArgList into an Args struct, mapping various argument types to their corresponding fields in Args. ```Rust impl From for Args { fn from(arg_list: ArgList) -> Args { use Arg::*; let mut args = Args::new(arg_list.item); for arg in arg_list.list { match arg { Merge(merge) => args.merge = Some(merge), Doc(doc) => args.doc = Some(doc), Rewrap(rewrap) => args.rewrap = rewrap, Attrs(attrs) => args.attrs = Some(attrs), FieldDocs(field_doc) => args.field_doc = field_doc, FieldAttrs(field_attrs) => args.field_attrs = Some(field_attrs), From(from) => args.from = from, } } args } } ``` -------------------------------- ### Test: replace_docs Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search=std%3A%3Avec Verifies that documentation attributes are replaced with new content when specified. ```rust #[test] fn replace_docs() { let item = parse_item(quote! { /// some /// old /// docs #[some_attr] struct S; }); let new_doc_text = r#"docs that will replace the old ones"#; let cases = vec![ quote! { Opt, doc = #new_doc_text }, quote! { Opt, doc = #new_doc_text, attrs }, quote! { Opt, doc = #new_doc_text, attrs = (new_attr), }, quote! { Opt, doc = #new_doc_text, attrs = add(new_attr), }, ]; let new_doc_attr = parse_attr(quote! { #[doc = #new_doc_text] }); let item_docs = doc_attrs(&item.attrs); for case in cases { let args = parse_args(case); let generated = generate(&item, &args); assert!(!attrs_contain_any(&generated, &item_docs)); } } ``` -------------------------------- ### Test Macro for Duplicate Argument Panics Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool A macro to generate tests that verify panics when duplicate arguments are provided to parse_args. ```Rust macro_rules! duplicate_arg_panics_test { ($attr:meta, $expected:literal) => { duplicate_arg_panics_test!($attr, $attr, $expected); }; ($attr:meta, $dup:meta, $expected:literal) => { paste::item! { #[test] #[should_panic(expected = $expected)] fn []() { parse_args(quote! { Opt, $attr, $dup }); } } }; } ``` -------------------------------- ### Parse Attribute List for Meta Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search= Parses a list of attributes into a meta item for use in code generation. ```rust #[test] fn parse_attr_list() { let meta_tokens = quote! { ( derive(Debug, Clone), serde(rename_all = "camelCase", default) ) }; let meta = Attrs::parse_attr_list.parse2(meta_tokens).unwrap(); let meta_attrs = parse_attrs(quote! { #(#[#meta])* }); let attrs = parse_attrs(quote! { #[derive(Debug, Clone)] #[serde(rename_all = "camelCase", default)] }); assert_eq!(meta_attrs, attrs); } ``` -------------------------------- ### Parse From Argument Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool Parses the `from` argument. This indicates that the optional field should be created from a source. ```rust #[test] fn parse_from() { let args = parse_args(quote! { Opt, from }); assert!(args.from); } ``` -------------------------------- ### Test: Replace Documentation Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Tests the scenario where original documentation attributes are replaced with new ones. It asserts that the generated attributes do not contain the old documentation. ```Rust use super::*; use crate::test_util::*; #[test] fn replace_docs() { let item = parse_item(quote! { /// some /// old /// docs #[some_attr] struct S; }); let new_doc_text = r#"docs that will replace the old ones"#; let cases = vec![ quote! { Opt, doc = #new_doc_text }, quote! { Opt, doc = #new_doc_text, attrs }, quote! { Opt, doc = #new_doc_text, attrs = (new_attr), }, quote! { Opt, doc = #new_doc_text, attrs = add(new_attr), }, ]; let new_doc_attr = parse_attr(quote! { #[doc = #new_doc_text] }); let item_docs = doc_attrs(&item.attrs); for case in cases { let args = parse_args(case); let generated = generate(&item, &args); assert!(!attrs_contain_any(&generated, &item_docs)); } } ``` -------------------------------- ### Rust Keywords for Optfield Arguments Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=std%3A%3Avec Defines custom keywords used for parsing arguments in the optfield crate, such as 'doc', 'merge_fn', and 'attrs'. ```rust mod kw { // NOTE: when adding new keywords update ArgList::next_is_kw syn::custom_keyword!(doc); syn::custom_keyword!(merge_fn); syn::custom_keyword!(rewrap); syn::custom_keyword!(attrs); syn::custom_keyword!(field_doc); syn::custom_keyword!(field_attrs); syn::custom_keyword!(from); pub mod attrs_sub { syn::custom_keyword!(add); } } ``` -------------------------------- ### Rust Struct for a List of Attributes Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=std%3A%3Avec A wrapper struct for a vector of `syn::Meta` to represent a list of attributes. ```rust #[derive(Debug)] pub struct AttrList(Vec); ``` -------------------------------- ### Attribute Order Awareness Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search= Note that `optfield` is a procedural macro and only processes attributes defined after it. Attributes placed before `#[optfield(...)]` are not visible to the macro. ```rust #[cfg(test)] // optfield is unaware of this attribute #[optfield(Opt, attrs)] #[derive(Debug)] struct MyStruct; ``` ```rust #[derive(Debug)] struct Opt; ``` -------------------------------- ### Test Case: Replace Docs Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search= Ensures that existing documentation attributes are replaced with new ones when a custom 'doc' argument is provided. This test covers various argument combinations. ```rust #[test] fn replace_docs() { let item = parse_item(quote! { /// some /// old /// docs #[some_attr] struct S; }); let new_doc_text = r#"docs that will replace the old ones"#; let cases = vec![ quote! { Opt, doc = #new_doc_text }, quote! { Opt, doc = #new_doc_text, attrs }, quote! { Opt, doc = #new_doc_text, attrs = (new_attr), }, quote! { Opt, doc = #new_doc_text, attrs = add(new_attr), }, ]; let new_doc_attr = parse_attr(quote! { #[doc = #new_doc_text] }); let item_docs = doc_attrs(&item.attrs); for case in cases { let args = parse_args(case); let generated = generate(&item, &args); assert!(!attrs_contain_any(&generated, &item_docs)); } } ``` -------------------------------- ### Using the optfield Attribute Macro Source: https://docs.rs/optfield/0.4.0/optfield/attr.optfield.html?search=std%3A%3Avec Apply the `#[optfield]` attribute macro to a struct to enable its field manipulation features. Refer to the crate documentation for detailed usage. ```rust #[optfield] ``` -------------------------------- ### Empty Arguments Panic Test Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html?search=u32+-%3E+bool Tests that parsing with an empty token stream correctly panics, expecting an 'expected opt struct name' error. ```Rust #[test] #[should_panic(expected = "expected opt struct name")] fn empty_args_panics() { parse_args(TokenStream::new()); } ``` -------------------------------- ### AttrList struct definition Source: https://docs.rs/optfield/0.4.0/src/optfield/args.rs.html A wrapper for a list of Meta attributes. ```rust #[derive(Debug)] pub struct AttrList(Vec); ``` -------------------------------- ### Unexpected Error Formatting Source: https://docs.rs/optfield/0.4.0/src/optfield/error.rs.html?search= Formats an unexpected error message with the given action. Use this when an unrecoverable error occurs. ```rust pub fn unexpected(action: String, err: E) -> String where E: std::error::Error + std::fmt::Display, { format!( "Unexpected error {}: {}\nPlease open an issue detailing how this happened!", action, err ) } ``` -------------------------------- ### Generate Optional Field Struct Source: https://docs.rs/optfield/0.4.0/optfield/index.html?search= Use the `optfield` macro to create a new struct with all fields from the original struct wrapped in Option. The original struct remains unchanged. ```Rust use optfield::optfield; #[optfield(Opt)] struct MyStruct { text: String } ``` ```Rust struct Opt { text: Option } ``` -------------------------------- ### Removing Attributes with OptionField Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Demonstrates how to remove existing attributes from an item using the `optfield` macro when 'Opt' is specified without further attribute manipulation. ```Rust let (item, args) = parse_item_and_args( quote! { #[some] #[attrs] struct S; }, quote! { Opt }, ); let generated = generate(&item, &args); assert!(!attrs_contain_any(&generated, &item.attrs)); ``` -------------------------------- ### Adding Attributes to Opt Struct Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Demonstrates using 'attrs = add(...)' to include original attributes along with new ones (e.g., #[cfg(test)], #[derive(Clone)]) in the generated optional struct. The generated struct includes both sets of attributes. ```rust # use optfield::*; #[optfield( Opt, attrs = add( cfg(test), derive(Clone) ) )] #[derive(Debug)] struct MyStruct { text: String } ``` ```rust #[derive(Debug)] #[cfg(test)] #[derive(Clone)] struct Opt { text: Option } ``` -------------------------------- ### Inserting Original Attributes Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Uses the 'attrs' argument to insert the same attributes (e.g., #[cfg(test)], #[derive(Clone)]) from the original struct to the generated optional struct. The original attributes are preserved. ```rust # use optfield::*; #[optfield(Opt, attrs)] #[cfg(test)] #[derive(Clone)] struct MyStruct { text: String } ``` ```rust #[cfg(test)] #[derive(Clone)] struct Opt { text: Option } ``` -------------------------------- ### Test: Keep Original Documentation Source: https://docs.rs/optfield/0.4.0/src/optfield/attrs/mod.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Tests the scenario where original documentation attributes should be preserved. It checks if generated attributes contain all original documentation. ```Rust use super::*; use crate::test_util::*; #[test] fn keep_same_docs() { let item = parse_item(quote! { /// some /// docs #[some_attr] struct S; }); let cases = vec![ quote! { Opt, doc }, quote! { Opt, doc, attrs }, quote! { Opt, doc, attrs = (new_attr) }, quote! { Opt, doc, attrs = add(new_attr) }, ]; let item_docs = doc_attrs(&item.attrs); for case in cases { let args = parse_args(case); let generated = generate(&item, &args); assert!(attrs_contain_all(&generated, &item_docs)); } } ``` -------------------------------- ### Adding Field Attributes Source: https://docs.rs/optfield/0.4.0/src/optfield/lib.rs.html?search=u32+-%3E+bool Shows how to use the `field_attrs` argument with the `add` directive to append new attributes to the struct's fields. ```rust # use optfield::*; # use serde::Deserialize; #[optfield( Opt, attrs, field_attrs = add( serde(default) ) )] #[derive(Deserialize)] struct MyStruct { #[serde(rename = "text")] my_text: String, #[serde(rename = "number")] my_number: i32 } // Will generate: #[derive(Deserialize)] struct Opt { #[serde(rename = "text")] #[serde(default)] my_text: Option, #[serde(rename = "number")] #[serde(default)] my_number: Option } ```