From 3f78ca57bae513ecb57870ab994360bcb0849aa5 Mon Sep 17 00:00:00 2001 From: Idan Arye Date: Mon, 14 Aug 2023 16:46:44 +0300 Subject: [PATCH] Close #109: Add `crate_module_path` --- CHANGELOG.md | 3 ++ src/lib.rs | 8 ++++ typed-builder-macro/src/field_info.rs | 4 +- typed-builder-macro/src/struct_info.rs | 59 +++++++++++++++++--------- typed-builder-macro/src/util.rs | 4 +- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 466f4e12..b9bbac91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- `#[builder(crate_module_path = ...)]` for overcoming cases where the derive + macro is used in another crate's macro (see issue #109) ## 0.15.2 - 2023-08-03 ### Fixed diff --git a/src/lib.rs b/src/lib.rs index b1125a39..a704bb03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,14 @@ use core::ops::FnOnce; /// but it won't be a link. If you turn this on, the builder type and its `build` method will get /// sane defaults. The field methods on the builder will be undocumented by default. /// +/// - `crate_module_path`: This is only needed when `typed_builder` is reexported from another +/// crate - which usually happens when another macro uses it. In that case, it is the +/// reponsibility of that macro to set the `crate_module_path` to the _unquoted_ module path from +/// which the `typed_builder` crate can be accessed, so that the `TypedBuilder` macro will be +/// able to access the typed declared in it. +/// +/// Defaults to `#[builder(crate_module_path=::typed_builder)]`. +/// /// - The following subsections: /// - `builder_method(...)`: customize the builder method that creates the builder type /// - `builder_type(...)`: customize the builder type diff --git a/typed-builder-macro/src/field_info.rs b/typed-builder-macro/src/field_info.rs index 69622441..021c8207 100644 --- a/typed-builder-macro/src/field_info.rs +++ b/typed-builder-macro/src/field_info.rs @@ -305,11 +305,11 @@ impl SetterSettings { Ok(()) } "prefix" => { - self.prefix = Some(expr_to_lit_string(&*assign.right)?); + self.prefix = Some(expr_to_lit_string(&assign.right)?); Ok(()) } "suffix" => { - self.suffix = Some(expr_to_lit_string(&*assign.right)?); + self.suffix = Some(expr_to_lit_string(&assign.right)?); Ok(()) } _ => Err(Error::new_spanned(&assign, format!("Unknown parameter {:?}", name))), diff --git a/typed-builder-macro/src/struct_info.rs b/typed-builder-macro/src/struct_info.rs index f6e70b1e..9fc63665 100644 --- a/typed-builder-macro/src/struct_info.rs +++ b/typed-builder-macro/src/struct_info.rs @@ -405,25 +405,18 @@ impl<'a> StructInfo<'a> { paren_token: None, lifetimes: None, modifier: syn::TraitBoundModifier::None, - path: syn::Path { - leading_colon: Some(syn::token::PathSep::default()), - segments: [ - syn::PathSegment { - ident: Ident::new("typed_builder", Span::call_site()), - arguments: syn::PathArguments::None, - }, - syn::PathSegment { - ident: Ident::new("Optional", Span::call_site()), - arguments: syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { - colon2_token: None, - lt_token: Default::default(), - args: [syn::GenericArgument::Type(field.ty.clone())].into_iter().collect(), - gt_token: Default::default(), - }), - }, - ] - .into_iter() - .collect(), + path: { + let mut path = self.builder_attr.crate_module_path.clone(); + path.segments.push(syn::PathSegment { + ident: Ident::new("Optional", Span::call_site()), + arguments: syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + colon2_token: None, + lt_token: Default::default(), + args: [syn::GenericArgument::Type(field.ty.clone())].into_iter().collect(), + gt_token: Default::default(), + }), + }); + path }, }; let mut generic_param: syn::TypeParam = field.generic_ident.clone().into(); @@ -463,7 +456,8 @@ impl<'a> StructInfo<'a> { if field.builder_attr.setter.skip.is_some() { quote!(let #name = #default;) } else { - quote!(let #name = ::typed_builder::Optional::into_value(#name, || #default);) + let crate_module_path = &self.builder_attr.crate_module_path; + quote!(let #name = #crate_module_path::Optional::into_value(#name, || #default);) } } else { quote!(let #name = #name.0;) @@ -619,7 +613,7 @@ impl BuildMethodSettings { } } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct TypeBuilderAttr<'a> { /// Whether to show docs for the `TypeBuilder` type (rather than hiding them). pub doc: bool, @@ -634,6 +628,21 @@ pub struct TypeBuilderAttr<'a> { pub build_method: BuildMethodSettings, pub field_defaults: FieldBuilderAttr<'a>, + + pub crate_module_path: syn::Path, +} + +impl Default for TypeBuilderAttr<'_> { + fn default() -> Self { + Self { + doc: Default::default(), + builder_method: Default::default(), + builder_type: Default::default(), + build_method: Default::default(), + field_defaults: Default::default(), + crate_module_path: syn::parse_quote!(::typed_builder), + } + } } impl<'a> TypeBuilderAttr<'a> { @@ -678,6 +687,14 @@ impl<'a> TypeBuilderAttr<'a> { ) }; match name.as_str() { + "crate_module_path" => { + if let syn::Expr::Path(crate_module_path) = assign.right.as_ref() { + self.crate_module_path = crate_module_path.path.clone(); + Ok(()) + } else { + Err(Error::new_spanned(&assign.right, "crate_module_path must be a path")) + } + } "builder_method_doc" => Err(gen_structure_depracation_error("builder_method", "doc")), "builder_type_doc" => Err(gen_structure_depracation_error("builder_type", "doc")), "build_method_doc" => Err(gen_structure_depracation_error("build_method", "doc")), diff --git a/typed-builder-macro/src/util.rs b/typed-builder-macro/src/util.rs index 647781aa..df94aa19 100644 --- a/typed-builder-macro/src/util.rs +++ b/typed-builder-macro/src/util.rs @@ -120,8 +120,8 @@ pub fn expr_to_lit_string(expr: &syn::Expr) -> Result { match expr { syn::Expr::Lit(lit) => match &lit.lit { syn::Lit::Str(str) => Ok(str.value()), - _ => return Err(Error::new_spanned(expr, "attribute only allows str values")), + _ => Err(Error::new_spanned(expr, "attribute only allows str values")), }, - _ => return Err(Error::new_spanned(expr, "attribute only allows str values")), + _ => Err(Error::new_spanned(expr, "attribute only allows str values")), } }