diff --git a/glib/src/param_spec.rs b/glib/src/param_spec.rs index 12bc5d159ad9..59bd4d5983b4 100644 --- a/glib/src/param_spec.rs +++ b/glib/src/param_spec.rs @@ -4,6 +4,7 @@ use std::{ char::CharTryFromError, convert::TryFrom, ffi::CStr, + num::{NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU32, NonZeroU64, NonZeroU8}, path::{Path, PathBuf}, }; @@ -2174,87 +2175,36 @@ impl HasParamSpec for char { Self::ParamSpec::builder } } -impl HasParamSpec for f64 { - type ParamSpec = ParamSpecDouble; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecDoubleBuilder; - - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } -} -impl HasParamSpec for f32 { - type ParamSpec = ParamSpecFloat; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecFloatBuilder; - - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } -} -impl HasParamSpec for i64 { - type ParamSpec = ParamSpecInt64; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecInt64Builder; - - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } -} -impl HasParamSpec for i32 { - type ParamSpec = ParamSpecInt; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecIntBuilder; - - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } -} -impl HasParamSpec for i8 { - type ParamSpec = ParamSpecChar; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecCharBuilder; +// Simple types which have `type SetValue = Self` +// and a builder function that doesn't require any parameter except the name +macro_rules! has_simple_spec { + ($t:ty, $s:ty, $b:ty) => { + impl HasParamSpec for $t { + type ParamSpec = $s; + type SetValue = Self; + type BuilderFn = fn(&str) -> $b; - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } -} -impl HasParamSpec for u64 { - type ParamSpec = ParamSpecUInt64; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecUInt64Builder; - - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } -} -impl HasParamSpec for u32 { - type ParamSpec = ParamSpecUInt; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecUIntBuilder; - - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } -} -impl HasParamSpec for u8 { - type ParamSpec = ParamSpecUChar; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecUCharBuilder; - - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } -} -impl HasParamSpec for bool { - type ParamSpec = ParamSpecBoolean; - type SetValue = Self; - type BuilderFn = fn(&str) -> ParamSpecBooleanBuilder; - - fn param_spec_builder() -> Self::BuilderFn { - Self::ParamSpec::builder - } + fn param_spec_builder() -> Self::BuilderFn { + Self::ParamSpec::builder + } + } + }; } +has_simple_spec!(f64, ParamSpecDouble, ParamSpecDoubleBuilder); +has_simple_spec!(f32, ParamSpecFloat, ParamSpecFloatBuilder); +has_simple_spec!(i64, ParamSpecInt64, ParamSpecInt64Builder); +has_simple_spec!(NonZeroI64, ParamSpecInt64, ParamSpecInt64Builder); +has_simple_spec!(i32, ParamSpecInt, ParamSpecIntBuilder); +has_simple_spec!(NonZeroI32, ParamSpecInt, ParamSpecIntBuilder); +has_simple_spec!(i8, ParamSpecChar, ParamSpecCharBuilder); +has_simple_spec!(NonZeroI8, ParamSpecChar, ParamSpecCharBuilder); +has_simple_spec!(u64, ParamSpecUInt64, ParamSpecUInt64Builder); +has_simple_spec!(NonZeroU64, ParamSpecUInt64, ParamSpecUInt64Builder); +has_simple_spec!(u32, ParamSpecUInt, ParamSpecUIntBuilder); +has_simple_spec!(NonZeroU32, ParamSpecUInt, ParamSpecUIntBuilder); +has_simple_spec!(u8, ParamSpecUChar, ParamSpecUCharBuilder); +has_simple_spec!(NonZeroU8, ParamSpecUChar, ParamSpecUCharBuilder); +has_simple_spec!(bool, ParamSpecBoolean, ParamSpecBooleanBuilder); impl HasParamSpec for crate::Variant { type ParamSpec = ParamSpecVariant; diff --git a/glib/src/types.rs b/glib/src/types.rs index b5366f404025..4cfa291e8b3a 100644 --- a/glib/src/types.rs +++ b/glib/src/types.rs @@ -7,6 +7,7 @@ use std::{ fmt, marker::PhantomData, mem, + num::{NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU32, NonZeroU64, NonZeroU8}, path::{Path, PathBuf}, ptr, }; @@ -491,11 +492,17 @@ impl PartialOrd for libc::c_ulong { builtin!(bool, BOOL); builtin!(i8, I8); +builtin!(NonZeroI8, I8); builtin!(u8, U8); +builtin!(NonZeroU8, U8); builtin!(i32, I32); +builtin!(NonZeroI32, I32); builtin!(u32, U32); +builtin!(NonZeroU32, U32); builtin!(i64, I64); +builtin!(NonZeroI64, I64); builtin!(u64, U64); +builtin!(NonZeroU64, U64); builtin!(ILong, I_LONG); builtin!(ULong, U_LONG); builtin!(f32, F32); diff --git a/glib/src/value.rs b/glib/src/value.rs index 8af6d6ea589d..6a3521ee1aa6 100644 --- a/glib/src/value.rs +++ b/glib/src/value.rs @@ -45,6 +45,7 @@ use std::{ error, ffi::CStr, fmt, mem, + num::{NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU32, NonZeroU64, NonZeroU8}, ops::Deref, path::{Path, PathBuf}, ptr, @@ -1244,37 +1245,90 @@ macro_rules! numeric { } }; } +macro_rules! not_zero { + ($name:ty, $num:ty) => { + impl ValueType for $name { + type Type = $name; + } + + unsafe impl<'a> FromValue<'a> for $name { + // Works because it returns `UnexpectedNone` if the value is NULL + // by checking it against `0`. + type Checker = GenericValueTypeOrNoneChecker; + + #[inline] + unsafe fn from_value(value: &'a Value) -> Self { + let res = <$num>::from_value(value); + Self::try_from(res).unwrap() + } + } + + impl ToValue for $name { + #[inline] + fn to_value(&self) -> Value { + <$num>::to_value(&<$num>::from(*self)) + } + + #[inline] + fn value_type(&self) -> Type { + Self::static_type() + } + } + + impl From<$name> for Value { + #[inline] + fn from(v: $name) -> Self { + v.to_value() + } + } + + impl ToValueOptional for $name { + fn to_value_optional(s: Option<&Self>) -> Value { + match s { + Some(x) => x.to_value(), + None => <$num>::to_value(&0), + } + } + } + }; +} numeric!( i8, gobject_ffi::g_value_get_schar, gobject_ffi::g_value_set_schar ); +not_zero!(NonZeroI8, i8); numeric!( u8, gobject_ffi::g_value_get_uchar, gobject_ffi::g_value_set_uchar ); +not_zero!(NonZeroU8, u8); numeric!( i32, gobject_ffi::g_value_get_int, gobject_ffi::g_value_set_int ); +not_zero!(NonZeroI32, i32); numeric!( u32, gobject_ffi::g_value_get_uint, gobject_ffi::g_value_set_uint ); +not_zero!(NonZeroU32, u32); numeric!( i64, gobject_ffi::g_value_get_int64, gobject_ffi::g_value_set_int64 ); +not_zero!(NonZeroI64, i64); numeric!( u64, gobject_ffi::g_value_get_uint64, gobject_ffi::g_value_set_uint64 ); +not_zero!(NonZeroU64, u64); numeric!( crate::ILong, |v| gobject_ffi::g_value_get_long(v).into(), @@ -1417,6 +1471,8 @@ impl ToValueOptional for BoxedValue { #[cfg(test)] mod tests { + use std::num::NonZeroI32; + use super::*; #[test] @@ -1557,6 +1613,21 @@ mod tests { none_v.get::(), Err(ValueTypeMismatchError::new(Type::STRING, Type::I32)) ); + + // Check handling of NonZeroT + let v = NonZeroI32::new(123).unwrap().to_value(); + assert_eq!(v.get::(), Ok(NonZeroI32::new(123).unwrap())); + + let v = 123i32.to_value(); + assert_eq!(v.get::(), Ok(NonZeroI32::new(123).unwrap())); + + let v = 0i32.to_value(); + assert_eq!( + v.get::(), + Err(ValueTypeMismatchOrNoneError::UnexpectedNone) + ); + + assert_eq!(v.get::>(), Ok(None)); } #[test]