### Derive SchemaInfo Trait for Structs - Rust Source: https://docs.rs/tryparse-derive/latest/tryparse_derive/derive This example demonstrates how to use the `#[derive(SchemaInfo)]` macro to automatically implement the `SchemaInfo` trait for a Rust struct. This trait is used for generating schema information, which can be useful for serialization, validation, or documentation purposes. The macro handles the boilerplate code required for trait implementation. ```Rust use tryparse::SchemaInfo; #[derive(SchemaInfo)] struct User { name: String, age: u32, } let schema = User::schema(); // Schema::Object { name: "User", fields: [...] } ``` -------------------------------- ### Derive SchemaInfo for Structs and Enums in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This macro derives the SchemaInfo trait for Rust structs and enums. It parses the input type, generates schema information based on whether it's a struct or an enum, and handles different field types (named, unnamed, unit) and enum variants. It requires the `tryparse` crate for schema definitions and `proc_macro2` and `syn` for macro implementation. ```rust use proc_macro::TokenStream; use quote::quote; use syn::{parse_macro_input, Data, DeriveInput, Fields, GenericArgument, PathArguments, Type}; /// Derives the `SchemaInfo` trait for a struct or enum. /// /// # Example /// /// ```ignore /// use tryparse::SchemaInfo; /// /// #[derive(SchemaInfo)] /// struct User { /// name: String, /// age: u32, /// } /// /// let schema = User::schema(); /// // Schema::Object { name: "User", fields: [...] } /// ``` #[proc_macro_derive(SchemaInfo)] pub fn derive_schema_info(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = &input.ident; let generics = &input.generics; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let schema_impl = match &input.data { Data::Struct(data_struct) => generate_struct_schema(name, data_struct), Data::Enum(data_enum) => generate_enum_schema(name, data_enum), Data::Union(_) => { return syn::Error::new_spanned(input, "SchemaInfo cannot be derived for unions") .to_compile_error() .into(); } }; let expanded = quote! { impl #impl_generics ::tryparse::schema::SchemaInfo for #name #ty_generics #where_clause { fn schema() -> ::tryparse::schema::Schema { #schema_impl } } }; TokenStream::from(expanded) } fn generate_struct_schema(name: &syn::Ident, data: &syn::DataStruct) -> proc_macro2::TokenStream { let name_str = name.to_string(); match &data.fields { Fields::Named(fields) => { let field_defs = fields.named.iter().map(|f| { let field_name = f.ident.as_ref().unwrap().to_string(); let field_type = &f.ty; quote! { ::tryparse::schema::Field::new( #field_name, <#field_type as ::tryparse::schema::SchemaInfo>::schema() ) } }); quote! { ::tryparse::schema::Schema::Object { name: #name_str.to_string(), fields: vec![#(#field_defs),*], } } } Fields::Unnamed(fields) => { // Treat tuple structs as tuples let field_types = fields.unnamed.iter().map(|f| { let ty = &f.ty; quote! { <#ty as ::tryparse::schema::SchemaInfo>::schema() } }); quote! { ::tryparse::schema::Schema::Tuple(vec![#(#field_types),*]) } } Fields::Unit => { // Unit struct is like null quote! { ::tryparse::schema::Schema::Null } } } } fn generate_enum_schema(name: &syn::Ident, data: &syn::DataEnum) -> proc_macro2::TokenStream { let name_str = name.to_string(); let variant_defs = data.variants.iter().map(|v| { let variant_name = v.ident.to_string(); let variant_schema = match &v.fields { Fields::Named(fields) => { // Variant with named fields - treat as object let field_defs = fields.named.iter().map(|f| { let field_name = f.ident.as_ref().unwrap().to_string(); let field_type = &f.ty; quote! { ::tryparse::schema::Field::new( #field_name, <#field_type as ::tryparse::schema::SchemaInfo>::schema() ) } }); quote! { ::tryparse::schema::Schema::Object { name: #variant_name.to_string(), fields: vec![#(#field_defs),*], } } } Fields::Unnamed(fields) => { // Variant with unnamed fields - treat as tuple let field_types = fields.unnamed.iter().map(|f| { let ty = &f.ty; quote! { <#ty as ::tryparse::schema::SchemaInfo>::schema() } }); quote! { ::tryparse::schema::Schema::Tuple(vec![#(#field_types),*]) } } }; quote! { ::tryparse::schema::Variant::new( #variant_name.to_string(), #variant_schema ) } }); quote! { ::tryparse::schema::Schema::Enum { name: #name_str.to_string(), variants: vec![#(#variant_defs),*], } } } ``` -------------------------------- ### Derive LlmDeserialize Macro for Structs in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib Implements the `LlmDeserialize` trait for Rust structs using procedural macros. This macro handles fuzzy field matching, optional fields, and type coercion based on BAML algorithms. It generates deserialization logic tailored for LLM interactions, supporting complex data structures. ```rust /// Derives the `LlmDeserialize` trait for a struct. /// /// This macro generates a custom deserialization implementation using BAML's /// algorithms for fuzzy field matching and type coercion. /// /// # Example /// /// ```ignore /// use tryparse::deserializer::LlmDeserialize; /// /// #[derive(LlmDeserialize)] /// struct User { /// name: String, /// age: u32, /// email: Option, // Optional field /// } /// /// // The macro generates an implementation that: /// // - Handles fuzzy field matching (userName → user_name) /// // - Supports optional fields with defaults /// // - Detects circular references /// // - Tracks transformations /// ``` #[proc_macro_derive(LlmDeserialize, attributes(llm))] pub fn derive_llm_deserialize(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = &input.ident; let generics = &input.generics; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); match &input.data { Data::Struct(data_struct) => { let deserialize_impl = generate_struct_deserialize(name, data_struct); let expanded = quote! { impl #impl_generics ::tryparse::deserializer::LlmDeserialize for #name #ty_generics #where_clause { #deserialize_impl } }; TokenStream::from(expanded) } Data::Enum(data_enum) => { // Check if this is a union enum (has #[llm(union)] attribute) let is_union = has_union_attribute(&input.attrs); let deserialize_impl = if is_union { generate_union_deserialize(name, data_enum, &input.attrs) } else { generate_enum_deserialize(name, data_enum, &input.attrs) }; let expanded = quote! { impl #impl_generics ::tryparse::deserializer::LlmDeserialize for #name #ty_generics #where_clause { #deserialize_impl } }; TokenStream::from(expanded) } Data::Union(_) => { syn::Error::new_spanned(input, "LlmDeserialize cannot be derived for unions") .to_compile_error() .into() } } } fn generate_struct_deserialize( name: &syn::Ident, data: &syn::DataStruct, ) -> proc_macro2::TokenStream { match &data.fields { Fields::Named(fields) => { let field_names: Vec<_> = fields.named.iter().map(|f| &f.ident).collect(); let field_types: Vec<_> = fields.named.iter().map(|f| &f.ty).collect(); let field_name_strs: Vec<_> = fields .named .iter() .map(|f| f.ident.as_ref().unwrap().to_string()) .collect(); // Check if each field is Option let is_optional: Vec<_> = field_types.iter().map(|ty| is_option_type(ty)).collect(); // Extract inner type for Option fields let inner_types: Vec<_> = field_types .iter() .zip(&is_optional) .map(|(ty, opt)| { if *opt { extract_option_inner(ty) } else { (*ty).clone() } }) .collect(); let name_str = name.to_string(); // Generate field descriptor setup (collect to Vec for reuse) let field_descriptors: Vec<_> = field_name_strs .iter() .zip(&field_types) .zip(&is_optional) .map(|((name, ty), opt)| { let type_name = quote!(stringify!(#ty)).to_string(); quote! { .field(::tryparse::deserializer::FieldDescriptor::new( #name, #type_name, #opt )) } }) .collect(); quote! { // ... implementation details for struct deserialization ... } } Fields::Unnamed(_) => { syn::Error::new_spanned(data, "Tuple structs are not supported for LlmDeserialize") .to_compile_error() .into() } Fields::Unit => { syn::Error::new_spanned(data, "Unit structs are not supported for LlmDeserialize") .to_compile_error() .into() } } } ``` -------------------------------- ### Struct Deserialization Logic in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This Rust code snippet outlines the deserialization logic for structs using the tryparse derive macro. It handles field name matching, strict deserialization attempting to deserialize into a specific type, and lenient deserialization falling back to a default. It also includes extraction of fields from a Box and constructing the struct. It explicitly does not support tuple or unit structs. ```rust #( #field_name_strs => { if strict { // Try strict deserialization if let Some(v) = <#inner_types as ::tryparse::deserializer::LlmDeserialize>::try_deserialize(field_value, field_ctx) { Ok(Box::new(v) as Box) } else { Err(::tryparse::error::ParseError::DeserializeFailed( ::tryparse::error::DeserializeError::type_mismatch( stringify!(#inner_types), "value" ) )) } } else { // Lenient deserialization let v = <#inner_types as ::tryparse::deserializer::LlmDeserialize>::deserialize(field_value, field_ctx)?; Ok(Box::new(v) as Box) } } )* _ => Err(::tryparse::error::ParseError::DeserializeFailed( ::tryparse::error::DeserializeError::Custom( format!("Unknown field: {}", field_name) ) )) } } )?; // Extract fields from Box (lenient mode - return error on failure) #(#field_extractions_lenient)* Ok(Self { #(#field_names),* }) } } } Fields::Unnamed(_) => syn::Error::new_spanned( data.fields.clone(), "LlmDeserialize does not support tuple structs yet", ) .to_compile_error(), Fields::Unit => syn::Error::new_spanned( data.fields.clone(), "LlmDeserialize does not support unit structs", ) .to_compile_error(), } } ``` -------------------------------- ### Rust: Generate Field Extraction for try_deserialize (Option) Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib Generates Rust code for extracting fields when performing strict deserialization, returning an Option. It handles both optional and required fields, returning None if a required field is missing. This code is intended for use within a derive macro context. ```rust let field_extractions_strict: Vec<_> = field_names .iter() .zip(&inner_types) .zip(&is_optional) .map(|((field_name, inner_ty), opt)| { let field_name_str = field_name.as_ref().unwrap().to_string(); if *opt { // Optional field quote! { let #field_name = fields.get(#field_name_str) .and_then(|v| v.downcast_ref::<#inner_ty>()) .cloned(); } } else { // Required field - return None if missing quote! { let #field_name = fields.get(#field_name_str) .and_then(|v| v.downcast_ref::<#inner_ty>()) .cloned()?; } } }) .collect(); ``` -------------------------------- ### Rust: Generate Field Extraction for deserialize (Result) Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib Generates Rust code for extracting fields during lenient deserialization, returning a Result. It handles optional fields by returning None if missing, and required fields by returning a ParseError if missing. This code is part of a derive macro. ```rust let field_extractions_lenient: Vec<_> = field_names.iter().zip(&inner_types).zip(&is_optional).map(|((field_name, inner_ty), opt)| { let field_name_str = field_name.as_ref().unwrap().to_string(); if *opt { // Optional field quote! { let #field_name = fields.get(#field_name_str) .and_then(|v| v.downcast_ref::<#inner_ty>()) .cloned(); } } else { // Required field quote! { let #field_name = fields.get(#field_name_str) .and_then(|v| v.downcast_ref::<#inner_ty>()) .cloned() .ok_or_else(|| ::tryparse::error::ParseError::DeserializeFailed( ::tryparse::error::DeserializeError::missing_field(#field_name_str) ))?; } } }).collect(); ``` -------------------------------- ### Rust: Implement try_deserialize for Structs Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib Generates the `try_deserialize` function for a struct using the TryParse derive macro. This function attempts to deserialize a `FlexValue` into the struct, returning an `Option`. It uses a `StructDeserializer` and handles field extraction in strict mode. ```rust quote! { fn try_deserialize( value: &::tryparse::value::FlexValue, ctx: &mut ::tryparse::deserializer::CoercionContext, ) -> Option { use std::any::Any; let mut deserializer = ::tryparse::deserializer::StructDeserializer::new() #(#field_descriptors)*; let fields = deserializer.try_deserialize( value, ctx, #name_str, |field_name, field_value, field_ctx| { // Dispatch to the appropriate field type's LlmDeserialize impl (strict mode only) match field_name { #( #field_name_strs => { // Try strict deserialization <#inner_types as ::tryparse::deserializer::LlmDeserialize>::try_deserialize(field_value, field_ctx) .map(|v| Box::new(v) as Box) } )* _ => None } } ).ok()?; // Extract fields from Box (strict mode - return None on failure) #(#field_extractions_strict)* Some(Self { #(#field_names),* }) } } ``` -------------------------------- ### Rust: Implement deserialize for Structs Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib Generates the `deserialize` function for a struct using the TryParse derive macro. This function deserializes a `FlexValue` into the struct, returning a `Result`. It utilizes a `StructDeserializer` and handles field extraction in both strict and lenient modes. ```rust quote! { fn deserialize( value: &::tryparse::value::FlexValue, ctx: &mut ::tryparse::deserializer::CoercionContext, ) -> ::tryparse::error::Result { use std::any::Any; let mut deserializer = ::tryparse::deserializer::StructDeserializer::new() #(#field_descriptors)*; let fields = deserializer.deserialize( value, ctx, #name_str, |field_name, field_value, field_ctx, strict| { // Dispatch to the appropriate field type's LlmDeserialize impl match field_name { ``` -------------------------------- ### Rust: Union Deserialization with Lenient Matching and Scoring Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This Rust code snippet implements a lenient matching algorithm for deserializing union types. It attempts to deserialize each variant, calculates a score based on transformation penalties, and selects the variant with the lowest score. It includes error handling for cases where no variant matches and adds a UnionMatch transformation to track the selected variant. ```rust // BAML ALGORITHM: Try lenient matching with scoring (coerce) struct MatchResult { variant: u8, // 1 or 2 score: u32, } let mut matches = Vec::new(); // Try variant 1 with separate FlexValue to track transformations let value1 = value.clone(); if let Ok(_) = <#variant1_type as LlmDeserialize>::deserialize(&value1, ctx) { let score: u32 = value1.transformations().iter().map(|t| t.penalty()).sum(); matches.push(MatchResult { variant: 1, score }); } // Try variant 2 with separate FlexValue to track transformations let value2 = value.clone(); if let Ok(_) = <#variant2_type as LlmDeserialize>::deserialize(&value2, ctx) { let score: u32 = value2.transformations().iter().map(|t| t.penalty()).sum(); matches.push(MatchResult { variant: 2, score }); } if matches.is_empty() { return Err(::tryparse::error::ParseError::DeserializeFailed( ::tryparse::error::DeserializeError::Custom( "No union variant matched".to_string() ) )); } // Sort by score (lower is better) matches.sort_by_key(|m| m.score); // Add UnionMatch transformation to track which variant was selected let variant_index = (matches[0].variant - 1) as usize; ctx.add_transformation(::tryparse::value::Transformation::UnionMatch { index: variant_index, candidates: vec![ stringify!(#variant1_type).to_string(), stringify!(#variant2_type).to_string(), ], }); // Deserialize the best match match matches[0].variant { 1 => { let v1 = <#variant1_type as LlmDeserialize>::deserialize(value, ctx)?; Ok(Self::#variant1_ident(v1)) } 2 => { let v2 = <#variant2_type as LlmDeserialize>::deserialize(value, ctx)?; Ok(Self::#variant2_ident(v2)) } _ => unreachable!(), } } } } ``` -------------------------------- ### Enum Deserialization Generation in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This Rust function `generate_enum_deserialize` generates the code for deserializing enum variants using the `tryparse` crate. It constructs `EnumVariant` definitions for each variant and creates match arms for handling different variant names. Currently, it only supports simple unit variants and returns an error for complex variants (named or unnamed), suggesting manual implementation for those cases. ```rust fn generate_enum_deserialize( name: &syn::Ident, data: &syn::DataEnum, _attrs: &[syn::Attribute], ) -> proc_macro2::TokenStream { let name_str = name.to_string(); // Build EnumMatcher setup with all variants let matcher_setup = data.variants.iter().map(|v| { let variant_name = v.ident.to_string(); quote! { .variant(::tryparse::deserializer::enum_coercer::EnumVariant::new(#variant_name)) } }); // Build match arms for each variant let match_arms = data.variants.iter().map(|v| { let variant_ident = &v.ident; let variant_name = v.ident.to_string(); match &v.fields { Fields::Unit => { // Simple unit variant (e.g., Status::Active) quote! { #variant_name => Ok(Self::#variant_ident), } } Fields::Named(_) | Fields::Unnamed(_) => { // Complex variants with fields - not yet supported in derive macro // Users can implement LlmDeserialize manually for these cases quote! { #variant_name => Err(::tryparse::error::ParseError::DeserializeFailed( ``` -------------------------------- ### Generate Schema Definition for Unions in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib Generates a schema definition for union types within the `tryparse` framework using Rust macros. This function is part of the `LlmDeserialize` derive macro, specifically handling enums marked with the `#[llm(union)]` attribute. It constructs a schema representation for variants, including their names and associated schemas. ```rust fn generate_union_deserialize( name: &syn::Ident, data_enum: &syn::DataEnum, attrs: &[syn::Attribute], ) -> proc_macro2::TokenStream { let variant_defs: Vec<_> = data_enum.variants.iter().map(|variant| { let variant_name = &variant.ident; let variant_name_str = variant_name.to_string(); // Determine the schema for the variant let variant_schema = match &variant.fields { Fields::Unit => { // Unit variant - like null quote! { ::tryparse::schema::Schema::Null } } Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { // Variant with a single unnamed field let field_type = &fields.unnamed[0].ty; quote! { ::tryparse::schema::Schema::from_type::<#field_type>() } } Fields::Named(fields) if fields.named.len() == 1 => { // Variant with a single named field let field_type = &fields.named[0].ty; quote! { ::tryparse::schema::Schema::from_type::<#field_type>() } } _ => { // For simplicity, other complex variants might need more sophisticated schema generation // or could be treated as unsupported for direct schema mapping here. // Defaulting to a placeholder or error might be necessary. syn::Error::new_spanned(variant, "Unsupported field structure for union variant schema generation").to_compile_error() } }; let variant_name_literal = syn::LitStr::new(&variant_name_str, variant.ident.span()); quote! { ::tryparse::schema::Variant::new(#variant_name_literal.to_string(), #variant_schema) } }).collect(); let name_str = name.to_string(); let name_literal = syn::LitStr::new(&name_str, name.span()); quote! { ::tryparse::schema::Schema::Union { name: #name_literal.to_string(), variants: vec![#(#variant_defs),*], } } } ``` -------------------------------- ### Enum Deserialization with derive macro in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This code snippet demonstrates the `deserialize` function generated by a derive macro for enum types. It utilizes a `FlexValue` and `CoercionContext` to match and construct enum variants, supporting fuzzy matching for variant identification. It handles errors for unknown variants. ```rust fn deserialize( value: &::tryparse::value::FlexValue, _ctx: &mut ::tryparse::deserializer::CoercionContext, ) -> ::tryparse::error::Result { // Build matcher with all enum variants let matcher = ::tryparse::deserializer::enum_coercer::EnumMatcher::new() #(#matcher_setup)*; // Use BAML's fuzzy matching to find the best variant let matched_variant = ::tryparse::deserializer::enum_coercer::match_enum_variant( value, &matcher )?; // Construct the matched variant match matched_variant.as_str() { #(#match_arms)* _ => Err(::tryparse::error::ParseError::DeserializeFailed( ::tryparse::error::DeserializeError::UnknownVariant { enum_name: #name_str.to_string(), variant: matched_variant, } )), } } ``` -------------------------------- ### Check for #[llm(union)] attribute in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This function checks if a given set of `syn::Attribute`s includes the specific `#[llm(union)]` attribute. It iterates through attributes, identifies those with the path `llm`, and then checks if their meta-list tokens contain the identifier `union`. ```rust fn has_union_attribute(attrs: &[syn::Attribute]) -> bool { attrs.iter().any(|attr| { if attr.path().is_ident("llm") { // Parse as #[llm(union)] if let Ok(meta_list) = attr.meta.require_list() { // Check if any nested item is "union" return meta_list.tokens.to_string().trim() == "union"; } } false }) } ``` -------------------------------- ### Generate Union Deserialization for Enums in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This function generates deserialization logic for enums marked with the `#[llm(union)]` attribute. It enforces that union enums must have exactly two variants, each containing a single unnamed field. It implements a two-step deserialization process: strict matching via `try_deserialize` and then adds a `UnionMatch` transformation for strict matches. ```rust fn generate_union_deserialize( name: &syn::Ident, data: &syn::DataEnum, _attrs: &[syn::Attribute], ) -> proc_macro2::TokenStream { if data.variants.len() != 2 { return syn::Error::new_spanned(name, "Union enums must have exactly 2 variants") .to_compile_error(); } let variants: Vec<_> = data.variants.iter().collect(); let variant1 = &variants[0]; let variant2 = &variants[1]; // Extract variant types let (variant1_ident, variant1_type) = match &variant1.fields { Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { (&variant1.ident, &fields.unnamed[0].ty) } _ => { return syn::Error::new_spanned( variant1, "Union variants must have exactly one unnamed field", ) .to_compile_error(); } }; let (variant2_ident, variant2_type) = match &variant2.fields { Fields::Unnamed(fields) if fields.unnamed.len() == 1 => { (&variant2.ident, &fields.unnamed[0].ty) } _ => { return syn::Error::new_spanned( variant2, "Union variants must have exactly one unnamed field", ) .to_compile_error(); } }; quote! { fn deserialize( value: &::tryparse::value::FlexValue, ctx: &mut ::tryparse::deserializer::CoercionContext, ) -> ::tryparse::error::Result { use ::tryparse::deserializer::LlmDeserialize; // BAML ALGORITHM: Try strict matching first (try_cast) if let Some(v1) = <#variant1_type as LlmDeserialize>::try_deserialize(value, ctx) { // Add UnionMatch transformation for strict match ctx.add_transformation(::tryparse::value::Transformation::UnionMatch { index: 0, candidates: vec![ stringify!(#variant1_type).to_string(), stringify!(#variant2_type).to_string(), ], }); return Ok(Self::#variant1_ident(v1)); } if let Some(v2) = <#variant2_type as LlmDeserialize>::try_deserialize(value, ctx) { // Add UnionMatch transformation for strict match ctx.add_transformation(::tryparse::value::Transformation::UnionMatch { index: 1, candidates: vec![ stringify!(#variant1_type).to_string(), stringify!(#variant2_type).to_string(), ], }); return Ok(Self::#variant2_ident(v2)); } } } } ``` -------------------------------- ### Extract Inner Type from Option in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This Rust function, `extract_option_inner`, takes a `Type` and returns the inner type `T` if the input is `Option`. It navigates the type path and generic arguments to find the enclosed type. If the input is not an `Option`, it returns the original type. This aids in processing generic types. ```rust /// Extract the inner type T from Option fn extract_option_inner(ty: &Type) -> Type { if let Type::Path(type_path) = ty { if let Some(segment) = type_path.path.segments.last() { if segment.ident == "Option" { if let PathArguments::AngleBracketed(args) = &segment.arguments { if let Some(GenericArgument::Type(inner)) = args.args.first() { return inner.clone(); } } } } } // Fallback: return the original type ty.clone() } ``` -------------------------------- ### Check if Type is Option in Rust Source: https://docs.rs/tryparse-derive/latest/src/tryparse_derive/lib This Rust function, `is_option_type`, checks if a given `Type` is an `Option`. It parses the type path and returns true if the last segment's identifier is 'Option'. This is useful for conditionally handling optional fields during deserialization. ```rust /// Check if a type is Option fn is_option_type(ty: &Type) -> bool { if let Type::Path(type_path) = ty { if let Some(segment) = type_path.path.segments.last() { return segment.ident == "Option"; } } false } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.