// Take a look at the license at the top of the repository in the LICENSE file. #[macro_export] macro_rules! bitflags_serialize_impl { // this implementation serializes only flags using only one bit, // ignoring all other flags ($type:ty, single_bit_flags$(, $feature:expr)?) => { $(#[cfg(any(feature = $feature, docsrs))] #[cfg_attr(docsrs, doc(cfg(feature = $feature)))])? impl serde::Serialize for $type { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let class = FlagsClass::with_type(Self::static_type()).unwrap(); let this = self.to_value(); let mut handled = Self::empty().to_value(); let mut res = String::new(); for v in class.values() { let value = v.value(); if value.count_ones() == 1 && class.is_set(&this, value) && !class.is_set(&handled, value) { if !res.is_empty() { res.push('+'); } res.push_str(v.nick()); handled = class.set(handled, value).expect("Failed to set flag"); } } serializer.serialize_str(&res) } } }; // considers the flags using the most bits first ($type:ty, by_ones_decreasing$(, $feature:expr)?) => { $(#[cfg(any(feature = $feature, docsrs))] #[cfg_attr(docsrs, doc(cfg(feature = $feature)))])? impl serde::Serialize for $type { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { let mut handled = Self::empty(); let mut res = String::new(); static SORTED_VALUES: std::sync::OnceLock> = std::sync::OnceLock::new(); let sorted_values = SORTED_VALUES.get_or_init(|| { let class = FlagsClass::with_type(<$type>::static_type()).unwrap(); let mut sorted_values: Vec<(u32, String)> = class.values().iter() .map(|f| (f.value(), f.nick().to_owned())) .collect(); sorted_values.sort_by(|(a, _), (b, _)| { b.count_ones().cmp(&a.count_ones()) }); sorted_values }); for (bits, nick) in sorted_values.iter() { // not all values defined in the class are always also defined // in the bitflags struct, see RTPBufferFlags for example if let Some(value) = Self::from_bits(*bits) { if !value.is_empty() && self.contains(value) && !handled.intersects(value) { if !res.is_empty() { res.push('+'); } res.push_str(nick); handled.insert(value); } } } serializer.serialize_str(&res) } } }; } #[macro_export] macro_rules! bitflags_deserialize_impl { ($type:ty$(, $feature:expr)?) => { $(#[cfg(any(feature = $feature, docsrs))] #[cfg_attr(docsrs, doc(cfg(feature = $feature)))])? impl<'de> serde::Deserialize<'de> for $type { fn deserialize>( deserializer: D, ) -> std::result::Result { skip_assert_initialized!(); struct FlagsVisitor; impl<'de> serde::de::Visitor<'de> for FlagsVisitor { type Value = $type; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str( "one or more mask names separated by plus signs, or the empty string", ) } fn visit_str( self, value: &str, ) -> std::result::Result { if value.is_empty() { return Ok(Self::Value::empty()); } let mut gvalue = unsafe { glib::Value::from_type_unchecked(Self::Value::static_type()) }; let tokens = value.split('+'); let class = FlagsClass::with_type(Self::Value::static_type()).unwrap(); for token in tokens { gvalue = class.set_by_nick(gvalue, token).map_err(|_| { serde::de::Error::custom(&format!("Invalid value: {}", token)) })?; } Ok(unsafe { from_glib(glib::gobject_ffi::g_value_get_flags( gvalue.to_glib_none().0, )) }) } } deserializer.deserialize_str(FlagsVisitor) } } }; } #[macro_export] macro_rules! bitflags_serde_impl { ($type:ty$(, $feature:expr)?) => { $crate::bitflags_serialize_impl!($type, single_bit_flags$(, $feature)?); $crate::bitflags_deserialize_impl!($type$(, $feature)?); }; }