diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 25797773ad03..84089e51f3a6 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -17,7 +17,7 @@ jobs: - stable - beta - nightly - - "1.48.0" + - "1.51.0" conf: - { name: "atk", features: "v2_34", nightly: "--all-features", test_sys: true } - { name: "cairo", features: "png,pdf,svg,ps,use_glib,v1_16,freetype,script,xcb,xlib,win32-surface", nightly: "--features 'png,pdf,svg,ps,use_glib,v1_16,freetype,script,xcb,xlib,win32-surface'", test_sys: true } @@ -119,7 +119,7 @@ jobs: - stable - beta - nightly - - "1.48.0" + - "1.51.0" steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 diff --git a/README.md b/README.md index 98c881ebeb53..a54f5b20d155 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ information about each crate, please refer to their `README.md` file in their di ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/atk/README.md b/atk/README.md index 3acf5dacb522..bdb1c70731c3 100644 --- a/atk/README.md +++ b/atk/README.md @@ -5,7 +5,7 @@ __Rust__ bindings and wrappers for __Atk__, part of [gtk-rs](https://github.com/ ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/cairo/README.md b/cairo/README.md index 355ffc3f28c7..38571ff6da33 100644 --- a/cairo/README.md +++ b/cairo/README.md @@ -6,7 +6,7 @@ __Rust__ bindings for Rust and wrappers for __Cairo__. ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/gdk-pixbuf/README.md b/gdk-pixbuf/README.md index 70404d304af5..1abf074b2e4e 100644 --- a/gdk-pixbuf/README.md +++ b/gdk-pixbuf/README.md @@ -4,7 +4,7 @@ __Rust__ bindings and wrappers for __Gdk-Pixbuf__. ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/gdk/README.md b/gdk/README.md index ff16cf11fa2f..3e7446209870 100644 --- a/gdk/README.md +++ b/gdk/README.md @@ -4,7 +4,7 @@ __Rust__ bindings and wrappers for __GDK__, part of [gtk-rs](https://github.com/ ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/gdkx11/README.md b/gdkx11/README.md index a517e3582b07..88e54bcb331f 100644 --- a/gdkx11/README.md +++ b/gdkx11/README.md @@ -4,7 +4,7 @@ __Rust__ bindings and wrappers for __GDKX11__, part of [gtk-rs](https://github.c ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/gio/README.md b/gio/README.md index b967762ac960..bf66b1c9dacd 100644 --- a/gio/README.md +++ b/gio/README.md @@ -4,7 +4,7 @@ __Rust__ bindings and wrappers for __GIO__, part of [gtk-rs](https://github.com/ ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/glib-macros/src/gboxed_shared_derive.rs b/glib-macros/src/gboxed_shared_derive.rs new file mode 100644 index 000000000000..71cf65107a73 --- /dev/null +++ b/glib-macros/src/gboxed_shared_derive.rs @@ -0,0 +1,181 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use crate::utils::{crate_ident_new, find_attribute_meta, find_nested_meta, parse_type_name}; +use proc_macro2::{Ident, TokenStream}; +use proc_macro_error::abort_call_site; +use quote::quote; + +fn gen_impl_set_value_optional(name: &Ident, crate_ident: &Ident) -> TokenStream { + let refcounted_type_prefix = refcounted_type_prefix(name, crate_ident); + + quote! { + impl #crate_ident::value::SetValueOptional for #name { + unsafe fn set_value_optional(value: &mut #crate_ident::value::Value, this: Option<&Self>) { + let ptr = match this { + Some(this) => #refcounted_type_prefix::into_raw(this.0.clone()), + None => std::ptr::null(), + }; + + #crate_ident::gobject_ffi::g_value_take_boxed( + #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(value).0, + ptr as *mut _, + ); + } + } + } +} + +fn gen_impl_from_value(name: &Ident, crate_ident: &Ident) -> TokenStream { + let refcounted_type_prefix = refcounted_type_prefix(name, crate_ident); + + quote! { + impl<'a> #crate_ident::value::FromValue<'a> for #name { + unsafe fn from_value(value: &'a #crate_ident::value::Value) -> Self { + let ptr = #crate_ident::gobject_ffi::g_value_dup_boxed( + #crate_ident::translate::ToGlibPtr::to_glib_none(value).0, + ); + assert!(!ptr.is_null()); + #name(#refcounted_type_prefix::from_raw(ptr as *mut _)) + } + } + } +} + +fn gen_ptr_to_option(name: &Ident, nullable: bool, crate_ident: &Ident) -> TokenStream { + let refcounted_type_prefix = refcounted_type_prefix(name, crate_ident); + + if nullable { + quote! { + if ptr.is_null() { + None + } else { + Some(#name(#refcounted_type_prefix::from_raw(ptr as *mut _))) + } + } + } else { + quote! { + assert!(!ptr.is_null()); + Some(#name(#refcounted_type_prefix::from_raw(ptr as *mut _))) + } + } +} + +fn refcounted_type(input: &syn::DeriveInput) -> Option<&syn::TypePath> { + let fields = match &input.data { + syn::Data::Struct(s) => &s.fields, + _ => return None, + }; + + let unnamed = match fields { + syn::Fields::Unnamed(u) if u.unnamed.len() == 1 => &u.unnamed[0], + _ => return None, + }; + + let refcounted = match &unnamed.ty { + syn::Type::Path(p) => p, + _ => return None, + }; + + Some(refcounted) +} + +fn refcounted_type_prefix(name: &Ident, crate_ident: &Ident) -> proc_macro2::TokenStream { + quote! { + <<#name as #crate_ident::subclass::shared::SharedType>::RefCountedType as #crate_ident::subclass::shared::RefCounted> + } +} + +pub fn impl_gshared_boxed(input: &syn::DeriveInput) -> proc_macro2::TokenStream { + let refcounted_type = match refcounted_type(input) { + Some(p) => p, + _ => abort_call_site!("derive(GSharedBoxed) requires struct MyStruct(T: RefCounted)"), + }; + + let name = &input.ident; + let gtype_name = match parse_type_name(&input, "gshared_boxed") { + Ok(v) => v, + Err(e) => abort_call_site!( + "{}: derive(GSharedBoxed) requires #[gshared_boxed(type_name = \"SharedTypeName\")]", + e + ), + }; + + let meta = find_attribute_meta(&input.attrs, "gshared_boxed") + .unwrap() + .unwrap(); + let nullable = find_nested_meta(&meta, "nullable").is_some(); + let crate_ident = crate_ident_new(); + let refcounted_type_prefix = refcounted_type_prefix(name, &crate_ident); + let ptr_to_option = gen_ptr_to_option(name, nullable, &crate_ident); + + let impl_from_value = if !nullable { + gen_impl_from_value(name, &crate_ident) + } else { + quote! {} + }; + + let impl_set_value_optional = if nullable { + gen_impl_set_value_optional(name, &crate_ident) + } else { + quote! {} + }; + + quote! { + impl #crate_ident::subclass::shared::SharedType for #name { + const NAME: &'static str = #gtype_name; + + type RefCountedType = #refcounted_type; + + fn get_type() -> #crate_ident::Type { + static mut TYPE_: #crate_ident::Type = #crate_ident::Type::INVALID; + static ONCE: ::std::sync::Once = ::std::sync::Once::new(); + + ONCE.call_once(|| { + let type_ = #crate_ident::subclass::shared::register_shared_type::(); + unsafe { + TYPE_ = type_; + } + }); + + unsafe { TYPE_ } + } + + fn from_refcounted(this: Self::RefCountedType) -> Self { + Self(this) + } + + fn into_refcounted(self) -> Self::RefCountedType { + self.0 + } + } + + impl #crate_ident::StaticType for #name { + fn static_type() -> #crate_ident::Type { + <#name as #crate_ident::subclass::shared::SharedType>::get_type() + } + } + + impl #crate_ident::value::SetValue for #name { + unsafe fn set_value(value: &mut #crate_ident::value::Value, this: &Self) { + let ptr = #refcounted_type_prefix::into_raw(this.0.clone()); + #crate_ident::gobject_ffi::g_value_take_boxed( + #crate_ident::translate::ToGlibPtrMut::to_glib_none_mut(value).0, + ptr as *mut _, + ); + } + } + + #impl_set_value_optional + + impl<'a> #crate_ident::value::FromValueOptional<'a> for #name { + unsafe fn from_value_optional(value: &'a #crate_ident::value::Value) -> Option { + let ptr = #crate_ident::gobject_ffi::g_value_dup_boxed( + #crate_ident::translate::ToGlibPtr::to_glib_none(value).0, + ); + #ptr_to_option + } + } + + #impl_from_value + } +} diff --git a/glib-macros/src/lib.rs b/glib-macros/src/lib.rs index ebda576e8f7d..9f13cb6221c2 100644 --- a/glib-macros/src/lib.rs +++ b/glib-macros/src/lib.rs @@ -3,6 +3,7 @@ mod clone; mod downgrade_derive; mod gboxed_derive; +mod gboxed_shared_derive; mod genum_derive; mod gerror_domain_derive; mod gflags_attribute; @@ -300,6 +301,34 @@ pub fn gboxed_derive(input: TokenStream) -> TokenStream { gen.into() } +/// Derive macro for defining a [`SharedType`]`::get_type` function and +/// the [`glib::Value`] traits. +/// +/// # Example +/// +/// ``` +/// use glib::prelude::*; +/// use glib::subclass::prelude::*; +/// +/// #[derive(Clone, Debug, PartialEq, Eq)] +/// struct MySharedInner { +/// foo: String, +/// } +/// #[derive(Clone, Debug, PartialEq, Eq, glib::GSharedBoxed)] +/// #[gshared_boxed(type_name = "MyShared")] +/// struct MyShared(std::sync::Arc); +/// ``` +/// +/// [`SharedType`]: subclass/shared/trait.SharedType.html +/// [`glib::Value`]: value/struct.Value.html +#[proc_macro_derive(GSharedBoxed, attributes(gshared_boxed))] +#[proc_macro_error] +pub fn gshared_boxed_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let gen = gboxed_shared_derive::impl_gshared_boxed(&input); + gen.into() +} + /// Attribute macro for defining flags using the `bitflags` crate. /// This macro will also define a `GFlags::get_type` function and /// the [`glib::Value`] traits. diff --git a/glib-macros/tests/test.rs b/glib-macros/tests/test.rs index fbe4452339d0..50cde3a9e0a6 100644 --- a/glib-macros/tests/test.rs +++ b/glib-macros/tests/test.rs @@ -5,7 +5,7 @@ use glib::prelude::*; use glib::subclass::prelude::*; use glib::translate::{FromGlib, ToGlib}; -use glib::{gflags, GBoxed, GEnum, GErrorDomain}; +use glib::{gflags, GBoxed, GEnum, GErrorDomain, GSharedBoxed}; #[test] fn derive_gerror_domain() { @@ -22,6 +22,72 @@ fn derive_gerror_domain() { assert!(matches!(err.kind::(), Some(TestError::Bad))); } +#[test] +fn derive_shared_arc() { + #[derive(Debug, Eq, PartialEq, Clone)] + struct MyInnerShared { + foo: String, + } + #[derive(Debug, Eq, PartialEq, Clone, GSharedBoxed)] + #[gshared_boxed(type_name = "MySharedType")] + struct MyShared(std::sync::Arc); + + assert_eq!(MyShared::get_type().name(), "MySharedType"); + + let p = MyShared(std::sync::Arc::new(MyInnerShared { + foo: String::from("bar"), + })); + + assert_eq!(std::sync::Arc::strong_count(&p.0), 1); + let v = p.to_value(); + assert_eq!(std::sync::Arc::strong_count(&p.0), 2); + let p_clone = v.get::().unwrap().unwrap(); + assert_eq!(std::sync::Arc::strong_count(&p.0), 3); + drop(p_clone); + assert_eq!(std::sync::Arc::strong_count(&p.0), 2); + drop(v); + assert_eq!(std::sync::Arc::strong_count(&p.0), 1); +} + +#[test] +fn derive_shared_arc_nullable() { + #[derive(Debug, Eq, PartialEq, Clone)] + struct MyInnerNullableShared { + foo: String, + } + #[derive(Clone, Debug, PartialEq, Eq, GSharedBoxed)] + #[gshared_boxed(type_name = "MyNullableSharedType", nullable)] + struct MyNullableShared(std::sync::Arc); + + assert_eq!(MyNullableShared::get_type().name(), "MyNullableSharedType"); + + let p = MyNullableShared(std::sync::Arc::new(MyInnerNullableShared { + foo: String::from("bar"), + })); + + assert_eq!(std::sync::Arc::strong_count(&p.0), 1); + let _v = p.to_value(); + assert_eq!(std::sync::Arc::strong_count(&p.0), 2); + + let p = Some(MyNullableShared(std::sync::Arc::new( + MyInnerNullableShared { + foo: String::from("foo"), + }, + ))); + + assert_eq!(std::sync::Arc::strong_count(&p.as_ref().unwrap().0), 1); + let v = p.to_value(); + assert_eq!(std::sync::Arc::strong_count(&p.as_ref().unwrap().0), 2); + assert_eq!( + p.as_ref().unwrap().0.foo, + v.get::().unwrap().unwrap().0.foo + ); + + let b: Option = None; + let v = b.to_value(); + assert_eq!(None, v.get::().unwrap()); +} + #[test] fn derive_genum() { #[derive(Debug, Eq, PartialEq, Clone, Copy, GEnum)] diff --git a/glib/README.md b/glib/README.md index 342de8b5bca3..b18b0bf730ef 100644 --- a/glib/README.md +++ b/glib/README.md @@ -4,7 +4,7 @@ __Rust__ bindings and wrappers for __GLib__, part of [gtk-rs](https://github.com ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/glib/src/lib.rs b/glib/src/lib.rs index ee506327c4bc..5e137ad4fc6f 100644 --- a/glib/src/lib.rs +++ b/glib/src/lib.rs @@ -88,6 +88,7 @@ pub use once_cell; pub use glib_macros::{ clone, gflags, object_interface, object_subclass, Downgrade, GBoxed, GEnum, GErrorDomain, + GSharedBoxed, }; pub use self::array::Array; diff --git a/glib/src/subclass/boxed.rs b/glib/src/subclass/boxed.rs index bbbdd37dc7f6..ab24e4984eca 100644 --- a/glib/src/subclass/boxed.rs +++ b/glib/src/subclass/boxed.rs @@ -67,7 +67,9 @@ pub fn register_boxed_type() -> crate::Type { #[cfg(test)] mod test { use super::*; - // GBoxed macro assumes 'glib' is in scope + // We rename the current crate as glib, since the macros in glib-macros + // generate the glib namespace through the crate_ident_new utility, + // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; use crate::value::ToValue; diff --git a/glib/src/subclass/mod.rs b/glib/src/subclass/mod.rs index be6339a90071..6741bb423bd4 100644 --- a/glib/src/subclass/mod.rs +++ b/glib/src/subclass/mod.rs @@ -249,6 +249,8 @@ pub mod object; #[macro_use] pub mod boxed; +pub mod shared; + pub mod signal; pub mod prelude { @@ -256,6 +258,7 @@ pub mod prelude { pub use super::boxed::BoxedType; pub use super::interface::{ObjectInterface, ObjectInterfaceExt, ObjectInterfaceType}; pub use super::object::{ObjectClassSubclassExt, ObjectImpl, ObjectImplExt}; + pub use super::shared::{RefCounted, SharedType}; pub use super::types::{ ClassStruct, InstanceStruct, IsImplementable, IsSubclassable, ObjectSubclass, ObjectSubclassExt, ObjectSubclassType, diff --git a/glib/src/subclass/object.rs b/glib/src/subclass/object.rs index b4d327238eb3..8be59c55bd00 100644 --- a/glib/src/subclass/object.rs +++ b/glib/src/subclass/object.rs @@ -224,6 +224,9 @@ mod test { use super::super::super::object::ObjectExt; use super::super::super::value::{ToValue, Value}; use super::*; + // We rename the current crate as glib, since the macros in glib-macros + // generate the glib namespace through the crate_ident_new utility, + // and that returns `glib` (and not `crate`) when called inside the glib crate use crate as glib; use crate::StaticType; diff --git a/glib/src/subclass/shared.rs b/glib/src/subclass/shared.rs new file mode 100644 index 000000000000..d78935af3553 --- /dev/null +++ b/glib/src/subclass/shared.rs @@ -0,0 +1,229 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +//! Module for registering shared types for Rust types. + +use crate::translate::*; + +pub unsafe trait RefCounted: Clone + Sized + 'static { + /// The inner type + type InnerType; + + /// The function used to increment the inner type refcount + unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType; + + /// Converts the RefCounted object to a raw pointer to InnerType + unsafe fn into_raw(self) -> *const Self::InnerType; + + /// Converts a raw pointer to InnerType to a RefCounted object + unsafe fn from_raw(this: *const Self::InnerType) -> Self; +} + +unsafe impl RefCounted for std::sync::Arc +where + T: 'static, +{ + type InnerType = T; + + unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType { + std::sync::Arc::increment_strong_count(this); + this + } + + unsafe fn into_raw(self) -> *const Self::InnerType { + std::sync::Arc::into_raw(self) + } + + unsafe fn from_raw(this: *const Self::InnerType) -> Self { + std::sync::Arc::from_raw(this) + } +} + +unsafe impl RefCounted for std::rc::Rc +where + T: 'static, +{ + type InnerType = T; + + unsafe fn ref_(this: *const Self::InnerType) -> *const Self::InnerType { + use std::mem::ManuallyDrop; + let this_rc = ManuallyDrop::new(std::rc::Rc::from_raw(this)); + std::rc::Rc::into_raw(ManuallyDrop::take(&mut this_rc.clone())) + } + + unsafe fn into_raw(self) -> *const Self::InnerType { + std::rc::Rc::into_raw(self) + } + + unsafe fn from_raw(this: *const Self::InnerType) -> Self { + std::rc::Rc::from_raw(this) + } +} + +/// Trait for defining shared types. +/// +/// Links together the type name with the type itself. +/// +/// See [`register_shared_type`] for registering an implementation of this trait +/// with the type system. +/// +/// [`register_shared_type`]: fn.register_shared_type.html +pub trait SharedType: Clone + Sized + 'static { + /// Shared type name. + /// + /// This must be unique in the whole process. + const NAME: &'static str; + + /// The inner refcounted type + type RefCountedType: RefCounted; + + /// Returns the type ID. + /// + /// This is usually defined via the [`Shared!`] derive macro. + /// + /// [`Shared!`]: ../../derive.Shared.html + fn get_type() -> crate::Type; + + /// Converts the SharedType into its inner RefCountedType + fn into_refcounted(self) -> Self::RefCountedType; + + /// Constructs a SharedType from a RefCountedType + fn from_refcounted(this: Self::RefCountedType) -> Self; +} + +/// Register a boxed `glib::Type` ID for `T`. +/// +/// This must be called only once and will panic on a second call. +/// +/// See [`Shared!`] for defining a function that ensures that +/// this is only called once and returns the type id. +/// +/// [`Shared!`]: ../../derive.Shared.html +pub fn register_shared_type() -> crate::Type { + unsafe { + use std::ffi::CString; + unsafe extern "C" fn shared_ref(v: ffi::gpointer) -> ffi::gpointer { + T::RefCountedType::ref_(v as *const ::InnerType) + as ffi::gpointer + } + unsafe extern "C" fn shared_unref(v: ffi::gpointer) { + let _ = T::RefCountedType::from_raw( + v as *const ::InnerType, + ); + } + + let type_name = CString::new(T::NAME).unwrap(); + if gobject_ffi::g_type_from_name(type_name.as_ptr()) != gobject_ffi::G_TYPE_INVALID { + panic!( + "Type {} has already been registered", + type_name.to_str().unwrap() + ); + } + + from_glib(gobject_ffi::g_boxed_type_register_static( + type_name.as_ptr(), + Some(shared_ref::), + Some(shared_unref::), + )) + } +} + +#[cfg(test)] +mod test { + use super::*; + // We rename the current crate as glib, since the macros in glib-macros + // generate the glib namespace through the crate_ident_new utility, + // and that returns `glib` (and not `crate`) when called inside the glib crate + use crate as glib; + use crate::value::ToValue; + + #[derive(Clone, Debug, PartialEq, Eq)] + struct MySharedInner { + foo: String, + } + + #[derive(Clone, Debug, PartialEq, Eq, glib::GSharedBoxed)] + #[gshared_boxed(type_name = "MySharedArc")] + struct MySharedArc(std::sync::Arc); + + #[derive(Clone, Debug, PartialEq, Eq, glib::GSharedBoxed)] + #[gshared_boxed(type_name = "MySharedRc")] + struct MySharedRc(std::rc::Rc); + + #[test] + fn test_register() { + assert_ne!(crate::Type::INVALID, MySharedArc::get_type()); + assert_ne!(crate::Type::INVALID, MySharedRc::get_type()); + } + + #[test] + fn test_value_arc() { + assert_ne!(crate::Type::INVALID, MySharedArc::get_type()); + + let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner { + foo: String::from("abc"), + })); + let v = b.to_value(); + let b2 = v.get_some::().unwrap(); + assert!(std::sync::Arc::ptr_eq(&b.0, &b2.0)); + } + + #[test] + fn test_value_rc() { + assert_ne!(crate::Type::INVALID, MySharedRc::get_type()); + + let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner { + foo: String::from("abc"), + })); + let v = b.to_value(); + let b2 = v.get_some::().unwrap(); + assert!(std::rc::Rc::ptr_eq(&b.0, &b2.0)); + } + + #[test] + fn same_ffi_pointer_arc() { + assert_ne!(crate::Type::INVALID, MySharedArc::get_type()); + + let b = MySharedArc::from_refcounted(std::sync::Arc::new(MySharedInner { + foo: String::from("abc"), + })); + + let inner_raw_ptr = std::sync::Arc::into_raw(b.clone().0); + + assert_eq!(std::sync::Arc::strong_count(&b.0), 2); + + let inner_raw_ptr_clone = + unsafe { ::RefCountedType::ref_(inner_raw_ptr) }; + + assert_eq!(std::sync::Arc::strong_count(&b.0), 3); + assert!(std::ptr::eq(inner_raw_ptr, inner_raw_ptr_clone)); + + let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr) }; + let _ = + unsafe { ::RefCountedType::from_raw(inner_raw_ptr_clone) }; + assert_eq!(std::sync::Arc::strong_count(&b.0), 1); + } + + #[test] + fn same_ffi_pointer_rc() { + assert_ne!(crate::Type::INVALID, MySharedRc::get_type()); + + let b = MySharedRc::from_refcounted(std::rc::Rc::new(MySharedInner { + foo: String::from("abc"), + })); + + let inner_raw_ptr = std::rc::Rc::into_raw(b.clone().0); + + assert_eq!(std::rc::Rc::strong_count(&b.0), 2); + + let inner_raw_ptr_clone = + unsafe { ::RefCountedType::ref_(inner_raw_ptr) }; + + assert_eq!(std::rc::Rc::strong_count(&b.0), 3); + assert!(std::ptr::eq(inner_raw_ptr, inner_raw_ptr_clone)); + + let _ = unsafe { ::RefCountedType::from_raw(inner_raw_ptr) }; + let _ = + unsafe { ::RefCountedType::from_raw(inner_raw_ptr_clone) }; + assert_eq!(std::rc::Rc::strong_count(&b.0), 1); + } +} diff --git a/graphene/README.md b/graphene/README.md index 1086f2593bd1..d08b3c11371d 100644 --- a/graphene/README.md +++ b/graphene/README.md @@ -4,7 +4,7 @@ __Rust__ bindings and wrappers for __Graphene__, part of [gtk-rs](https://github ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/gtk/README.md b/gtk/README.md index 64a4e93d81b2..2dcd90ed476a 100644 --- a/gtk/README.md +++ b/gtk/README.md @@ -6,7 +6,7 @@ __Rust__ bindings and wrappers for __GTK 3__, part of [gtk-rs](https://github.co ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Building diff --git a/pango/README.md b/pango/README.md index 1dae7fa9b9c6..ace6f832ea52 100644 --- a/pango/README.md +++ b/pango/README.md @@ -4,7 +4,7 @@ __Rust__ bindings and wrappers for __Pango__, part of [gtk-rs](https://github.co ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation diff --git a/pangocairo/README.md b/pangocairo/README.md index b30b0f8aa1a5..739cbc599f8d 100644 --- a/pangocairo/README.md +++ b/pangocairo/README.md @@ -4,7 +4,7 @@ __Rust__ bindings and wrappers for __PangoCairo__, part of [gtk-rs](https://gith ## Minimum supported Rust version -Currently, the minimum supported Rust version is `1.48.0`. +Currently, the minimum supported Rust version is `1.51.0`. ## Documentation