Skip to content

Commit 55056ec

Browse files
authored
Merge pull request #579 from ranfdev/char_to_value
impl `ToValue`, `FromValue` for char
2 parents 081bc4e + 01fed42 commit 55056ec

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

glib/src/value.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,51 @@ unsafe impl<T: StaticType> ValueTypeChecker for GenericValueTypeChecker<T> {
158158
}
159159
}
160160

161+
pub struct CharTypeChecker();
162+
unsafe impl ValueTypeChecker for CharTypeChecker {
163+
type Error = InvalidCharError;
164+
165+
fn check(value: &Value) -> Result<(), Self::Error> {
166+
let v = value.get::<u32>()?;
167+
match char::from_u32(v) {
168+
Some(_) => Ok(()),
169+
None => Err(InvalidCharError::CharConversionError),
170+
}
171+
}
172+
}
173+
174+
// rustdoc-stripper-ignore-next
175+
/// An error returned from the [`get`](struct.Value.html#method.get) function
176+
/// on a [`Value`](struct.Value.html) for char (which are internally u32) types.
177+
#[derive(Clone, PartialEq, Eq, Debug)]
178+
pub enum InvalidCharError {
179+
WrongValueType(ValueTypeMismatchError),
180+
CharConversionError,
181+
}
182+
impl fmt::Display for InvalidCharError {
183+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184+
match self {
185+
Self::WrongValueType(err) => err.fmt(f),
186+
Self::CharConversionError => {
187+
write!(f, "couldn't convert to char, invalid u32 contents")
188+
}
189+
}
190+
}
191+
}
192+
impl error::Error for InvalidCharError {}
193+
194+
impl From<ValueTypeMismatchError> for InvalidCharError {
195+
fn from(err: ValueTypeMismatchError) -> Self {
196+
Self::WrongValueType(err)
197+
}
198+
}
199+
200+
impl From<Infallible> for InvalidCharError {
201+
fn from(e: Infallible) -> Self {
202+
match e {}
203+
}
204+
}
205+
161206
// rustdoc-stripper-ignore-next
162207
/// An error returned from the [`get`](struct.Value.html#method.get)
163208
/// function on a [`Value`](struct.Value.html) for optional types.
@@ -980,6 +1025,34 @@ numeric!(
9801025
gobject_ffi::g_value_set_double
9811026
);
9821027

1028+
impl ValueType for char {
1029+
type Type = u32;
1030+
}
1031+
1032+
unsafe impl<'a> FromValue<'a> for char {
1033+
type Checker = CharTypeChecker;
1034+
1035+
unsafe fn from_value(value: &'a Value) -> Self {
1036+
let res: u32 = gobject_ffi::g_value_get_uint(value.to_glib_none().0);
1037+
// safe because the check is done by `Self::Checker`
1038+
char::from_u32_unchecked(res)
1039+
}
1040+
}
1041+
1042+
impl ToValue for char {
1043+
fn to_value(&self) -> Value {
1044+
let mut value = Value::for_value_type::<Self>();
1045+
unsafe {
1046+
gobject_ffi::g_value_set_uint(&mut value.inner, *self as u32);
1047+
}
1048+
value
1049+
}
1050+
1051+
fn value_type(&self) -> Type {
1052+
crate::Type::U32
1053+
}
1054+
}
1055+
9831056
// rustdoc-stripper-ignore-next
9841057
/// A [`Value`] containing another [`Value`].
9851058
pub struct BoxedValue(pub Value);
@@ -1141,6 +1214,15 @@ mod tests {
11411214
Err(ValueTypeMismatchError::new(Type::STRING, Type::I32))
11421215
);
11431216

1217+
let c_v = 'c'.to_value();
1218+
assert_eq!(c_v.get::<char>(), Ok('c'));
1219+
1220+
let c_v = 0xFFFFFFFFu32.to_value();
1221+
assert_eq!(
1222+
c_v.get::<char>(),
1223+
Err(InvalidCharError::CharConversionError)
1224+
);
1225+
11441226
// Check if &T and Option<&T> can be converted and retrieved
11451227
let v_str = (&String::from("test")).to_value();
11461228
assert_eq!(v_str.get::<String>(), Ok(String::from("test")));

0 commit comments

Comments
 (0)