Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 140 additions & 70 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cairo/src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl Device {
}

#[doc(alias = "cairo_device_acquire")]
pub fn acquire(&self) -> Result<DeviceAcquireGuard, Error> {
pub fn acquire(&self) -> Result<DeviceAcquireGuard<'_>, Error> {
unsafe {
let status = ffi::cairo_device_acquire(self.to_raw_none());
status_to_result(status)?;
Expand Down
2 changes: 1 addition & 1 deletion cairo/src/image_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl ImageSurface {

#[doc(alias = "cairo_image_surface_get_data")]
#[doc(alias = "get_data")]
pub fn data(&mut self) -> Result<ImageSurfaceData, BorrowError> {
pub fn data(&mut self) -> Result<ImageSurfaceData<'_>, BorrowError> {
unsafe {
if ffi::cairo_surface_get_reference_count(self.to_raw_none()) > 1 {
return Err(BorrowError::NonExclusive);
Expand Down
2 changes: 1 addition & 1 deletion cairo/src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl Path {
Path(ptr::NonNull::new_unchecked(pointer))
}

pub fn iter(&self) -> PathSegments {
pub fn iter(&self) -> PathSegments<'_> {
use std::slice;

unsafe {
Expand Down
12 changes: 12 additions & 0 deletions examples/object_subclass/author.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,20 @@ mod imp {
#[derive(Properties, Default)]
#[properties(wrapper_type = super::Author)]
pub struct Author {
/// The name of the author
///
/// Just their given name, not their surname.
#[property(get, set)]
/// A helpful name-surname combination.
#[property(name = "name-surname", get = |author: &Self| format!("{} {}", author.name.borrow(), author.surname.borrow()))]
name: RefCell<String>,
/// # Getter
///
/// This is how you can get the surname of the author.
///
/// # Setter
///
/// You can change the surname of the author too if you want.
#[property(get, set)]
surname: RefCell<String>,
}
Expand Down
2 changes: 1 addition & 1 deletion gio/src/list_model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub trait ListModelExtManual: sealed::Sealed + IsA<ListModel> + Sized {
/// # Panics
///
/// Panics if `T::static_type().is_a(self.item_type())` is not true.
fn iter<LT: IsA<glib::Object>>(&self) -> ListModelIter<LT> {
fn iter<LT: IsA<glib::Object>>(&self) -> ListModelIter<'_, LT> {
assert!(self.item_type().is_a(LT::static_type()));

let len = self.n_items();
Expand Down
2 changes: 1 addition & 1 deletion gio/src/unix_socket_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ mod sealed {
pub trait UnixSocketAddressExtManual: sealed::Sealed + IsA<UnixSocketAddress> + 'static {
#[doc(alias = "g_unix_socket_address_get_path")]
#[doc(alias = "get_path")]
fn path(&self) -> Option<UnixSocketAddressPath> {
fn path(&self) -> Option<UnixSocketAddressPath<'_>> {
use self::UnixSocketAddressPath::*;

let path = unsafe {
Expand Down
34 changes: 33 additions & 1 deletion glib-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ pub fn closure_local(item: TokenStream) -> TokenStream {
/// }
/// ```
///
/// When using the [`Properties`] macro with enums that derive [`Enum`], the default value must be
/// explicitly set via the `builder` parameter of the `#[property]` attribute. See
/// [here](Properties#supported-types) for details.
///
/// An enum can be registered as a dynamic type by setting the derive macro
/// helper attribute `enum_dynamic`:
///
Expand Down Expand Up @@ -1381,6 +1385,10 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
/// * `connect_$property_notify()`
/// * `notify_$property()`
///
/// # Documentation
///
/// Doc comments preceding a `#[property]` attribute will be copied to the generated getter and setter methods. You can specify different comments by the getter and setter by using `# Getter` and `# Setter` headings. The text under the header will be copied to the respective method.
///
/// ## Extension trait
/// You can choose to move the method definitions to a trait by using `#[properties(wrapper_type = super::MyType, ext_trait = MyTypePropertiesExt)]`.
/// The trait name is optional, and defaults to `MyTypePropertiesExt`, where `MyType` is extracted from the wrapper type.
Expand All @@ -1399,6 +1407,9 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
/// Optional types also require the `nullable` attribute: without it, the generated setter on the wrapper type
/// will take `T` instead of `Option<T>`, preventing the user from ever calling the setter with a `None` value.
///
/// Notice: For enums that derive [`Enum`] or are C-style enums, you must explicitly specify the
/// default value of the enum using the `builder` parameter in the `#[property]` attribute.
///
/// ## Adding support for custom types
/// ### Types wrapping an existing <code>T: [ToValue] + [HasParamSpec]</code>
/// If you have declared a newtype as
Expand All @@ -1423,7 +1434,7 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
///
/// # Example
/// ```
/// use std::cell::RefCell;
/// use std::cell::{Cell, RefCell};
/// use glib::prelude::*;
/// use glib::subclass::prelude::*;
/// use glib_macros::Properties;
Expand All @@ -1434,6 +1445,14 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
/// nick: String,
/// }
///
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::Enum, Default)]
/// #[enum_type(name = "MyEnum")]
/// pub enum MyEnum {
/// #[default]
/// Val,
/// OtherVal
/// }
///
/// pub mod imp {
/// use std::rc::Rc;
///
Expand All @@ -1444,7 +1463,9 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
/// pub struct Foo {
/// #[property(get, set = Self::set_fizz)]
/// fizz: RefCell<String>,
/// /// The author's name
/// #[property(name = "author-name", get, set, type = String, member = name)]
/// /// The author's childhood nickname
/// #[property(name = "author-nick", get, set, type = String, member = nick)]
/// author: RefCell<Author>,
/// #[property(get, set, explicit_notify, lax_validation)]
Expand All @@ -1457,6 +1478,17 @@ pub fn cstr_bytes(item: TokenStream) -> TokenStream {
/// optional: RefCell<Option<String>>,
/// #[property(get, set)]
/// smart_pointer: Rc<RefCell<String>>,
/// #[property(get, set, builder(MyEnum::Val))]
/// my_enum: Cell<MyEnum>,
/// /// # Getter
/// ///
/// /// Get the value of the property `extra_comments`
/// ///
/// /// # Setter
/// ///
/// /// This is the comment for the setter of the `extra_comments` field.
/// #[property(get, set)]
/// extra_comments: RefCell<bool>,
/// }
///
/// #[glib::derived_properties]
Expand Down
105 changes: 84 additions & 21 deletions glib-macros/src/properties.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use syn::parse::Parse;
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
use syn::Token;
use syn::{parse_quote_spanned, LitStr};
use syn::{parse_quote_spanned, Attribute, LitStr};

pub struct PropsMacroInput {
wrapper_ty: syn::Path,
Expand Down Expand Up @@ -255,6 +255,7 @@ struct PropDesc {
field_ident: syn::Ident,
ty: syn::Type,
name: syn::LitStr,
comments: Vec<Attribute>,
override_class: Option<syn::Type>,
override_interface: Option<syn::Type>,
nullable: bool,
Expand All @@ -271,6 +272,7 @@ impl PropDesc {
attrs_span: proc_macro2::Span,
field_ident: syn::Ident,
field_ty: syn::Type,
comments: Vec<Attribute>,
attrs: ReceivedAttrs,
) -> syn::Result<Self> {
let ReceivedAttrs {
Expand Down Expand Up @@ -321,6 +323,7 @@ impl PropDesc {
field_ident,
ty,
name,
comments,
override_class,
override_interface,
nullable,
Expand Down Expand Up @@ -524,26 +527,33 @@ fn expand_set_property_fn(props: &[PropDesc]) -> TokenStream2 {
}

fn parse_fields(fields: syn::Fields) -> syn::Result<Vec<PropDesc>> {
fields
.into_iter()
.flat_map(|field| {
let syn::Field {
ident, attrs, ty, ..
} = field;
attrs
.into_iter()
.filter(|a| a.path().is_ident("property"))
.map(move |prop_attrs| {
let span = prop_attrs.span();
PropDesc::new(
span,
ident.as_ref().unwrap().clone(),
ty.clone(),
prop_attrs.parse_args()?,
)
})
})
.collect::<syn::Result<_>>()
let mut properties = vec![];

for field in fields.into_iter() {
let syn::Field {
ident, attrs, ty, ..
} = field;
// Store the comments until the next `#[property]` we see and then attach them to it.
let mut comments: Vec<Attribute> = vec![];
for prop_attr in attrs.iter() {
if prop_attr.path().is_ident("doc") {
comments.push(prop_attr.clone());
} else if prop_attr.path().is_ident("property") {
let span = prop_attr.span();
let existing_comments = comments;
comments = vec![];
properties.push(PropDesc::new(
span,
ident.as_ref().unwrap().clone(),
ty.clone(),
existing_comments,
prop_attr.parse_args()?,
)?);
}
}
}

Ok(properties)
}

/// Converts a glib property name to a correct rust ident
Expand All @@ -559,6 +569,50 @@ fn strip_raw_prefix_from_name(name: &LitStr) -> LitStr {
)
}

/// Splits the comments for a property between the getter and setter
///
/// The return tuple is the attributes to copy over into the getter and setter
/// respectively.
fn arrange_property_comments(comments: &[Attribute]) -> (Vec<&Attribute>, Vec<&Attribute>) {
let mut untagged = vec![];
let mut getter = vec![];
let mut setter = vec![];
let mut saw_section = false;

// We start with no tags so if the programmer doesn't split the comments we can still arrange them.
let mut current_section = &mut untagged;
for attr in comments {
if let syn::Meta::NameValue(meta) = &attr.meta {
if let syn::Expr::Lit(expr) = &meta.value {
if let syn::Lit::Str(lit_str) = &expr.lit {
// Now that we have the one line of comment, see if we need
// to switch a particular section to be the active one (via
// the header syntax) or add the current line to the active
// section.
match lit_str.value().trim() {
"# Getter" => {
current_section = &mut getter;
saw_section = true;
}
"# Setter" => {
current_section = &mut setter;
saw_section = true;
}
_ => current_section.push(attr),
}
}
}
}
}

// If no sections were defined then we put the same in both
if !saw_section {
return (untagged.clone(), untagged);
}

(getter, setter)
}

fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
let crate_ident = crate_ident_new();
let defs = props.iter().filter(|p| !p.is_overriding()).map(|p| {
Expand All @@ -567,9 +621,12 @@ fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
let ident = name_to_ident(name);
let ty = &p.ty;

let (getter_docs, setter_docs) = arrange_property_comments(&p.comments);

let getter = p.get.is_some().then(|| {
let span = p.attrs_span;
parse_quote_spanned!(span=>
#(#getter_docs)*
#[must_use]
#[allow(dead_code)]
pub fn #ident(&self) -> <#ty as #crate_ident::property::Property>::Value {
Expand Down Expand Up @@ -597,12 +654,14 @@ fn expand_impl_getset_properties(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
};
let span = p.attrs_span;
parse_quote_spanned!(span=>
#(#setter_docs)*
#[allow(dead_code)]
pub fn #ident<'a>(&self, value: #set_ty) {
self.set_property_from_value(#stripped_name, &::std::convert::From::from(#upcasted_borrowed_value))
}
)
});

[getter, setter]
});
defs.flatten() // flattens []
Expand All @@ -617,7 +676,9 @@ fn expand_impl_connect_prop_notify(props: &[PropDesc]) -> Vec<syn::ImplItemFn> {
let stripped_name = strip_raw_prefix_from_name(name);
let fn_ident = format_ident!("connect_{}_notify", name_to_ident(name));
let span = p.attrs_span;
let doc = format!("Listen for notifications of a change in the `{}` property", name.value());
parse_quote_spanned!(span=>
#[doc = #doc]
#[allow(dead_code)]
pub fn #fn_ident<F: Fn(&Self) + 'static>(&self, f: F) -> #crate_ident::SignalHandlerId {
self.connect_notify_local(::core::option::Option::Some(#stripped_name), move |this, _| {
Expand All @@ -636,7 +697,9 @@ fn expand_impl_notify_prop(wrapper_type: &syn::Path, props: &[PropDesc]) -> Vec<
let fn_ident = format_ident!("notify_{}", name_to_ident(&name));
let span = p.attrs_span;
let enum_ident = name_to_enum_ident(name.value());
let doc = format!("Notify listeners of a change in the `{}` property", name.value());
parse_quote_spanned!(span=>
#[doc = #doc]
#[allow(dead_code)]
pub fn #fn_ident(&self) {
self.notify_by_pspec(
Expand Down
4 changes: 2 additions & 2 deletions glib/src/collections/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,14 @@ impl<T: TransparentPtrType> List<T> {
// rustdoc-stripper-ignore-next
/// Create a non-destructive iterator over the `List`.
#[inline]
pub fn iter(&self) -> Iter<T> {
pub fn iter(&self) -> Iter<'_, T> {
Iter::new(self)
}

// rustdoc-stripper-ignore-next
/// Create a non-destructive mutable iterator over the `List`.
#[inline]
pub fn iter_mut(&mut self) -> IterMut<T> {
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
IterMut::new(self)
}

Expand Down
18 changes: 13 additions & 5 deletions glib/src/collections/ptr_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,13 +658,21 @@ impl<T: TransparentPtrType> PtrSlice<T> {
/// This is guaranteed to be `NULL`-terminated.
#[inline]
pub fn into_raw(mut self) -> *mut <T as GlibPtrDefault>::GlibType {
// Make sure to allocate a valid pointer that points to a
// NULL-pointer.
if self.len == 0 {
ptr::null_mut()
} else {
self.len = 0;
self.capacity = 0;
self.ptr.as_ptr()
self.reserve(0);
unsafe {
ptr::write(
self.ptr.as_ptr().add(0),
Ptr::from(ptr::null_mut::<<T as GlibPtrDefault>::GlibType>()),
);
}
}

self.len = 0;
self.capacity = 0;
self.ptr.as_ptr()
}

// rustdoc-stripper-ignore-next
Expand Down
Loading
Loading