Skip to content

Commit 28a7413

Browse files
carlosmnbilelmoussaoui
authored andcommitted
glib-macros: Properties: allow setting getter and setter docs
In the previous commit we made it so we copy the docs for a `#[property]` in to the getter. This was an improvement but it still did not allow for any doc comments on the setter that might be relevant only there. Here we introduce the ability to specify doc comments for the getter and setter individually via the use of the header syntax to switch between them. By writing `# Getter` or `# Setter` in a line, you make the lines following it go to the getter or setter function definitions. If neither of these values exist, we copy the doc comments to both. If you use these values, then anything in the doc comments before the first one is discarded.
1 parent 0f5448c commit 28a7413

File tree

2 files changed

+63
-3
lines changed

2 files changed

+63
-3
lines changed

examples/object_subclass/author.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ mod imp {
2121
/// A helpful name-surname combination.
2222
#[property(name = "name-surname", get = |author: &Self| format!("{} {}", author.name.borrow(), author.surname.borrow()))]
2323
name: RefCell<String>,
24+
/// # Getter
25+
///
26+
/// This is how you can get the surname of the author.
27+
///
28+
/// # Setter
29+
///
30+
/// You can change the surname of the author too if you want.
2431
#[property(get, set)]
2532
surname: RefCell<String>,
2633
}

glib-macros/src/properties.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,50 @@ fn strip_raw_prefix_from_name(name: &LitStr) -> LitStr {
569569
)
570570
}
571571

572+
/// Splits the comments for a property between the getter and setter
573+
///
574+
/// The return tuple is the attributes to copy over into the getter and setter
575+
/// respectively.
576+
fn arrange_property_comments(comments: &[Attribute]) -> (Vec<&Attribute>, Vec<&Attribute>) {
577+
let mut untagged = vec![];
578+
let mut getter = vec![];
579+
let mut setter = vec![];
580+
let mut saw_section = false;
581+
582+
// We start with no tags so if the programmer doesn't split the comments we can still arrange them.
583+
let mut current_section = &mut untagged;
584+
for attr in comments {
585+
if let syn::Meta::NameValue(meta) = &attr.meta {
586+
if let syn::Expr::Lit(expr) = &meta.value {
587+
if let syn::Lit::Str(lit_str) = &expr.lit {
588+
// Now that we have the one line of comment, see if we need
589+
// to switch a particular section to be the active one (via
590+
// the header syntax) or add the current line to the active
591+
// section.
592+
match lit_str.value().trim() {
593+
"# Getter" => {
594+
current_section = &mut getter;
595+
saw_section = true;
596+
}
597+
"# Setter" => {
598+
current_section = &mut setter;
599+
saw_section = true;
600+
}
601+
_ => current_section.push(attr),
602+
}
603+
}
604+
}
605+
}
606+
}
607+
608+
// If no sections were defined then we put the same in both
609+
if !saw_section {
610+
return (untagged.clone(), untagged);
611+
}
612+
613+
(getter, setter)
614+
}
615+
572616
fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
573617
let crate_ident = crate_ident_new();
574618
let defs = props.iter().filter(|p| !p.is_overriding()).map(|p| {
@@ -577,6 +621,8 @@ fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
577621
let ident = name_to_ident(name);
578622
let ty = &p.ty;
579623

624+
let (getter_docs, setter_docs) = arrange_property_comments(&p.comments);
625+
580626
let mut getter: Option<syn::ImplItemFn> = p.get.is_some().then(|| {
581627
let span = p.attrs_span;
582628
parse_quote_spanned!(span=>
@@ -589,12 +635,12 @@ fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
589635
});
590636

591637
if let Some(ref mut getter) = getter {
592-
for lit in &p.comments {
593-
getter.attrs.push(lit.clone());
638+
for attr in getter_docs {
639+
getter.attrs.push(attr.clone());
594640
}
595641
}
596642

597-
let setter = (p.set.is_some() && !p.is_construct_only).then(|| {
643+
let mut setter: Option<syn::ImplItemFn> = (p.set.is_some() && !p.is_construct_only).then(|| {
598644
let ident = format_ident!("set_{}", ident);
599645
let target_ty = quote!(<<#ty as #crate_ident::property::Property>::Value as #crate_ident::prelude::HasParamSpec>::SetValue);
600646
let set_ty = if p.nullable {
@@ -619,6 +665,13 @@ fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
619665
}
620666
)
621667
});
668+
669+
if let Some(ref mut setter) = setter {
670+
for attr in setter_docs {
671+
setter.attrs.push(attr.clone());
672+
}
673+
}
674+
622675
[getter, setter]
623676
});
624677
defs.flatten() // flattens []

0 commit comments

Comments
 (0)