diff --git a/Cargo.toml b/Cargo.toml index 91175ac..a2f6f6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ members = ["filecaster", "filecaster-derive"] [workspace.dependencies] serde = { version = "1.0", features = ["derive"] } -merge = "0.2.0" +merge = "0.2" # dev-dependencies claims = "0.8" serde_json = "1.0" diff --git a/filecaster-derive/Cargo.toml b/filecaster-derive/Cargo.toml index 4d5f598..2fe7232 100644 --- a/filecaster-derive/Cargo.toml +++ b/filecaster-derive/Cargo.toml @@ -7,7 +7,8 @@ edition = "2024" proc-macro = true [features] -default = [] +default = ["serde"] +serde = ["dep:serde"] merge = ["dep:merge"] [dependencies] @@ -15,7 +16,7 @@ proc-macro2 = "1.0" quote = "1.0" proc-macro-error2 = "2.0" syn = { version = "2.0", features = ["extra-traits", "parsing"] } -serde.workspace = true +serde = { workspace = true, optional = true } merge = { workspace = true, optional = true } [dev-dependencies] diff --git a/filecaster-derive/src/from_file.rs b/filecaster-derive/src/from_file.rs index 2ba28d8..b3c6b31 100644 --- a/filecaster-derive/src/from_file.rs +++ b/filecaster-derive/src/from_file.rs @@ -1,5 +1,3 @@ -use std::path::PathBuf; - use proc_macro2::TokenStream; use quote::{format_ident, quote}; use syn::{ @@ -72,23 +70,6 @@ fn extract_named_fields(input: &DeriveInput) -> Result<&FieldsNamed> { } } -/// Nested-struct detection -fn is_from_file_struct(ty: &Type) -> bool { - if let Type::Path(TypePath { qself: None, path }) = ty { - return path.segments.len() == 1; - } - false -} - -/// Extract the last identifier from a [`TypePath`]. -fn last_path_ident(ty: &Type) -> Result { - if let Type::Path(TypePath { qself: None, path }) = ty { - return Ok(path.segments.last().unwrap().ident.to_string()); - } - - Err(Error::new_spanned(ty, "expected a plain struct name")) -} - /// Build the shadow field + assignment for one original field fn build_file_field(field: &Field) -> Result<(TokenStream, TokenStream, Option)> { let ident = field @@ -159,14 +140,10 @@ fn build_where_clause( /// Derive clause for the shadow struct fn build_derive_clause() -> TokenStream { - if WITH_MERGE { - return quote! { - #[derive(Debug, Clone, Default, serde::Deserialize, serde::Serialize, merge::Merge)] - }; - } - quote! { - #[derive(Debug, Clone, Default, serde::Deserialize, serde::Serialize)] + #[derive(Debug, Clone, Default)] + #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] + #[cfg_attr(feature = "merge", derive(merge::Merge))] } } @@ -332,21 +309,6 @@ mod tests { assert_eq!(preds, vec!["Z : Eq".to_string()]); } - #[test] - fn build_derive_clause_defaults() { - let derive_ts = build_derive_clause(); - let s = derive_ts.to_string(); - if WITH_MERGE { - assert!(s.contains( - "derive (Debug , Clone , Default , serde :: Deserialize , serde :: Serialize , merge :: Merge)" - )); - } else { - assert!(s.contains( - "derive (Debug , Clone , Default , serde :: Deserialize , serde :: Serialize)" - )); - } - } - #[test] fn add_trait_bouds_appends_default() { let gens: Generics = parse_quote!(); diff --git a/filecaster/Cargo.toml b/filecaster/Cargo.toml index 41d9f34..ad50b4b 100644 --- a/filecaster/Cargo.toml +++ b/filecaster/Cargo.toml @@ -14,13 +14,14 @@ exclude = ["/.github", "/.gitignore", "/tests", "*.png", "*.md"] readme = "README.md" [features] -default = ["derive"] +default = ["serde", "derive"] derive = ["dep:filecaster-derive"] +serde = ["dep:serde", "filecaster-derive/serde"] merge = ["dep:merge", "filecaster-derive/merge"] [dependencies] filecaster-derive = { path = "../filecaster-derive", optional = true } -serde.workspace = true +serde = { workspace = true, optional = true } merge = { workspace = true, optional = true } [dev-dependencies] diff --git a/filecaster/src/lib.rs b/filecaster/src/lib.rs index da91ab2..65454f5 100644 --- a/filecaster/src/lib.rs +++ b/filecaster/src/lib.rs @@ -1,4 +1,5 @@ pub use filecaster_derive::FromFile; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; /// Marker for types that can be built from an `Option` produced by the macro. @@ -6,9 +7,13 @@ pub trait FromFile: Sized { fn from_file(file: Option) -> Self; /// Associated shadow type generated by the macro. + #[cfg(feature = "serde")] type Shadow: Default + Serialize + for<'de> Deserialize<'de>; + #[cfg(not(feature = "serde"))] + type Shadow: Default; } +#[cfg(feature = "serde")] impl FromFile for T where T: Default + Serialize + for<'de> Deserialize<'de>, @@ -18,3 +23,14 @@ where file.unwrap_or_default() } } + +#[cfg(not(feature = "serde"))] +impl FromFile for T +where + T: Default, +{ + type Shadow = T; + fn from_file(file: Option) -> Self { + file.unwrap_or_default() + } +}