Skip to content

Commit

Permalink
Merge pull request #146 from sunsided/feature/copy-doc-comments
Browse files Browse the repository at this point in the history
Apply field doc-comments to builder methods
  • Loading branch information
idanarye authored Jun 15, 2024
2 parents b367f33 + 391bbf7 commit 20f59ae
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 10 deletions.
9 changes: 7 additions & 2 deletions examples/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ use typed_builder::TypedBuilder;

#[derive(Debug, PartialEq, TypedBuilder)]
struct Foo {
// Mandatory Field:
/// `x` value.
///
/// This field is mandatory.
x: i32,

// #[builder(default)] without parameter - use the type's default
// #[builder(setter(strip_option))] - wrap the setter argument with `Some(...)`
#[builder(default, setter(strip_option))]
#[builder(
default,
setter(strip_option, doc = "Set `y`. If you don't specify a value it'll default to no value.",)
)]
y: Option<i32>,

// Or you can set the default
Expand Down
3 changes: 3 additions & 0 deletions tests/no_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,13 @@ fn test_into() {
fn test_default() {
#[derive(PartialEq, TypedBuilder)]
struct Foo {
/// x value.
#[builder(default, setter(strip_option))]
x: Option<i32>,
#[builder(default = 10)]
/// y value.
y: i32,
/// z value.
#[builder(default = [20, 30, 40])]
z: [i32; 3],
}
Expand Down
19 changes: 15 additions & 4 deletions typed-builder-macro/src/field_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub struct FieldBuilderAttr<'a> {
pub default: Option<syn::Expr>,
pub via_mutators: Option<ViaMutators>,
pub deprecated: Option<&'a syn::Attribute>,
pub doc_comments: Vec<&'a syn::Expr>,
pub setter: SetterSettings,
/// Functions that are able to mutate fields in the builder that are already set
pub mutators: Vec<Mutator>,
Expand Down Expand Up @@ -153,10 +154,20 @@ impl<'a> FieldBuilderAttr<'a> {

list
}
syn::Meta::Path(path) | syn::Meta::NameValue(syn::MetaNameValue { path, .. }) => {
if path_to_single_string(path).as_deref() == Some("deprecated") {
self.deprecated = Some(attr);
};
syn::Meta::NameValue(syn::MetaNameValue { path, value, .. }) => {
match path_to_single_string(path).as_deref() {
Some("deprecated") => self.deprecated = Some(attr),
Some("doc") => self.doc_comments.push(value),
_ => continue,
}

continue;
}
syn::Meta::Path(path) => {
match path_to_single_string(path).as_deref() {
Some("deprecated") => self.deprecated = Some(attr),
_ => continue,
}

continue;
}
Expand Down
23 changes: 19 additions & 4 deletions typed-builder-macro/src/struct_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,25 @@ impl<'a> StructInfo<'a> {
target_generics.push(syn::GenericArgument::Type(target_generics_tuple.into()));
ty_generics.push(syn::GenericArgument::Type(ty_generics_tuple.into()));
let (impl_generics, _, where_clause) = generics.split_for_impl();
let doc = field.builder_attr.setter.doc.as_ref().map(|doc| quote!(#[doc = #doc]));
let doc = if let Some(doc) = field.builder_attr.setter.doc.as_ref() {
Some(quote!(#[doc = #doc]))
} else if !field.builder_attr.doc_comments.is_empty() {
Some(
field
.builder_attr
.doc_comments
.iter()
.map(|&line| quote!(#[doc = #line]))
.collect(),
)
} else {
None
};

let deprecated = &field.builder_attr.deprecated;

// NOTE: both auto_into and strip_option affect `arg_type` and `arg_expr`, but the order of
// nesting is different so we have to do this little dance.
// nesting is different, so we have to do this little dance.
let arg_type = if field.builder_attr.setter.strip_option.is_some() && field.builder_attr.setter.transform.is_none() {
field
.type_from_inside_option()
Expand Down Expand Up @@ -320,6 +334,7 @@ impl<'a> StructInfo<'a> {
#[deprecated(
note = #repeated_fields_error_message
)]
#doc
pub fn #method_name (self, _: #repeated_fields_error_type_name) -> #builder_name <#target_generics> {
self
}
Expand Down Expand Up @@ -354,8 +369,8 @@ impl<'a> StructInfo<'a> {
let mut generics = self.generics.clone();
for f in self.included_fields() {
if f.builder_attr.default.is_some() || f.builder_attr.via_mutators.is_some() {
// `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need
// to warn about missing `field` whether or not `f` is set.
// `f` is not mandatory - it does not have its own fake `build` method, so `field` will need
// to warn about missing `field` regardless of whether `f` is set.
assert!(
f.ordinal != field.ordinal,
"`required_field_impl` called for optional field {}",
Expand Down

0 comments on commit 20f59ae

Please sign in to comment.