use {
crate::lua::{LuaError, LuaTable, LuaType, LuaVariant},
glib::{variant::VariantTypeMismatchError, Variant, VariantTy},
serde::de::{self, IntoDeserializer, Visitor},
std::borrow::Cow,
};
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
pub fn from_variant<'de, D: de::Deserialize<'de>, V: AsRef<Variant>>(v: V) -> Result<D, LuaError> {
LuaVariant::convert_from(v.as_ref()).and_then(|v| D::deserialize(v.into_deserializer()))
}
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
#[derive(Debug, Clone)]
pub struct Deserializer<'a> {
variant: LuaVariant<'a>,
humanize: bool,
}
impl<'a> Deserializer<'a> {
pub fn new(variant: LuaVariant<'a>) -> Self {
Self {
variant,
humanize: true,
}
}
pub fn inhuman(self) -> Self {
Self {
variant: self.variant,
humanize: false,
}
}
fn change_variant<'v, V: Into<LuaVariant<'v>>>(&self, variant: V) -> Deserializer<'v> {
Deserializer {
variant: variant.into(),
humanize: self.humanize,
}
}
fn error(&self, wanted: &VariantTy) -> LuaError {
LuaError::TypeMismatch(VariantTypeMismatchError::new(
self.variant.flattened().as_variant().type_().to_owned(),
wanted.to_owned(),
))
}
fn unsupported(&self) -> LuaError {
LuaError::UnsupportedType(Cow::Owned(self.variant.flattened().as_variant().type_().to_owned()))
}
fn try_num<T, E: Into<LuaError>>(&self, v: Option<Result<T, E>>, wanted: &VariantTy) -> Result<T, LuaError> {
match v {
Some(res) => res.map_err(Into::into),
None => Err(self.error(wanted)),
}
}
fn try_get_float(&self) -> Result<f64, LuaError> {
match self.variant.flattened().get_float() {
Some(res) => res,
None => Err(self.error(VariantTy::DOUBLE)),
}
}
fn str(&self) -> Result<Cow<str>, LuaError> {
match self.variant.flattened().inner_ref() {
Err(v) => v.str().map(|s| Cow::Owned(s.into())),
Ok(v) => v.str().map(Cow::Borrowed),
}
.ok_or_else(|| self.error(VariantTy::STRING))
}
}
impl<'a, 'de> de::Deserializer<'de> for Deserializer<'a> {
type Error = LuaError;
fn is_human_readable(&self) -> bool {
self.humanize
}
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
match self.variant.lua_type() {
LuaType::Nil => self.deserialize_unit(visitor),
LuaType::Boolean => self.deserialize_bool(visitor),
LuaType::Integer => self.deserialize_i64(visitor),
LuaType::Float => self.deserialize_f64(visitor),
LuaType::String => self.deserialize_str(visitor),
LuaType::Table if self.variant.get_table().expect("LuaType").is_array().unwrap_or(true) =>
self.deserialize_seq(visitor),
LuaType::Table => self.deserialize_map(visitor),
}
}
fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_bool(self.variant.get_bool().ok_or_else(|| self.error(VariantTy::BOOLEAN))?)
}
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_i8(self.try_num(self.variant.get_integer(), VariantTy::INT16)?)
}
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_i16(self.try_num(self.variant.get_integer(), VariantTy::INT16)?)
}
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_i32(self.try_num(self.variant.get_integer(), VariantTy::INT32)?)
}
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_i64(self.try_num(self.variant.get_integer(), VariantTy::INT64)?)
}
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_u8(self.try_num(self.variant.get_integer(), VariantTy::BYTE)?)
}
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_u16(self.try_num(self.variant.get_integer(), VariantTy::UINT16)?)
}
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_u32(self.try_num(self.variant.get_integer(), VariantTy::UINT32)?)
}
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_u64(self.try_num(self.variant.get_integer(), VariantTy::UINT64)?)
}
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_f32(self.try_get_float()? as f32)
}
fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_f64(self.try_get_float()?)
}
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
self.deserialize_str(visitor)
}
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_str(&self.str()?)
}
fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_string(self.str()?.into_owned())
}
fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
match self.variant.lua_type() {
LuaType::String => self.deserialize_str(visitor),
LuaType::Table => visitor.visit_seq(SeqDeserializer::new(
self.clone().variant.get_table().unwrap().iter_array(),
self,
)),
_ => Err(self.error(VariantTy::BYTE_STRING)),
}
}
fn deserialize_byte_buf<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
self.deserialize_bytes(visitor)
}
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
match self.variant.lua_type() {
LuaType::Nil => visitor.visit_unit(),
_ => visitor.visit_some(self),
}
}
fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
self.variant.get_nil().ok_or_else(|| self.error(VariantTy::UNIT))?;
match self.variant.lua_type() {
LuaType::Nil => visitor.visit_unit(),
_ => Err(self.error(VariantTy::UNIT)),
}
}
fn deserialize_unit_struct<V: Visitor<'de>>(self, _name: &'static str, visitor: V) -> Result<V::Value, Self::Error> {
self.deserialize_unit(visitor)
}
fn deserialize_newtype_struct<V: Visitor<'de>>(
self,
_name: &'static str,
visitor: V,
) -> Result<V::Value, Self::Error> {
visitor.visit_newtype_struct(self)
}
fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
match self.variant.lua_type() {
LuaType::Table => visitor.visit_seq(SeqDeserializer::new(
self.clone().variant.get_table().unwrap().iter_array(),
self,
)),
_ => Err(self.error(VariantTy::ARRAY)),
}
}
fn deserialize_tuple<V: Visitor<'de>>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> {
match self.variant.lua_type() {
LuaType::Nil => visitor.visit_unit(),
LuaType::Table => match self.variant.get_table().expect("LuaType").array_len() {
actual if actual != len as u64 => Err(LuaError::LengthMismatch {
actual: actual as usize,
expected: len,
}),
_ => self.deserialize_seq(visitor),
},
_ => Err(self.error(VariantTy::TUPLE)),
}
}
fn deserialize_tuple_struct<V: Visitor<'de>>(
self,
_name: &'static str,
len: usize,
visitor: V,
) -> Result<V::Value, Self::Error> {
self.deserialize_tuple(len, visitor)
}
fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_map(MapDeserializer::new(self))
}
fn deserialize_struct<V: Visitor<'de>>(
self,
_name: &'static str,
_fields: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error> {
let table = self
.variant
.get_table()
.ok_or_else(|| self.error(VariantTy::DICTIONARY))?;
if table.is_array().unwrap_or(false) {
self.deserialize_seq(visitor)
} else {
self.deserialize_map(visitor)
}
}
fn deserialize_enum<V: Visitor<'de>>(
self,
_name: &'static str,
_variants: &'static [&'static str],
visitor: V,
) -> Result<V::Value, Self::Error> {
match self.variant.lua_type() {
LuaType::Table => visitor.visit_enum(EnumDeserializer::new(self)),
_ => visitor.visit_enum(UnitEnumDeserializer::new(self)),
}
}
fn deserialize_ignored_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
visitor.visit_unit()
}
fn deserialize_identifier<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
match self.variant.lua_type() {
LuaType::Integer => self.deserialize_i64(visitor),
LuaType::Float => self.deserialize_f64(visitor),
LuaType::String => self.deserialize_str(visitor),
_ => Err(self.error(VariantTy::OBJECT_PATH)),
}
}
}
#[repr(transparent)]
struct EnumDeserializer<'v> {
_de: Deserializer<'v>,
}
impl<'v> EnumDeserializer<'v> {
fn new(de: Deserializer<'v>) -> Self {
Self { _de: de }
}
}
impl<'v, 'de> de::EnumAccess<'de> for EnumDeserializer<'v> {
type Error = LuaError;
type Variant = Self;
fn variant_seed<V: de::DeserializeSeed<'de>>(self, _seed: V) -> Result<(V::Value, Self::Variant), Self::Error> {
Err(LuaError::Custom(format!(
"unimplemented wireplumber::lua::EnumDeserializer::variant_seed"
)))
}
}
impl<'v, 'de> de::VariantAccess<'de> for EnumDeserializer<'v> {
type Error = LuaError;
fn unit_variant(self) -> Result<(), Self::Error> {
Err(LuaError::Custom(format!(
"unimplemented wireplumber::lua::EnumDeserializer::unit_variant"
)))
}
fn newtype_variant_seed<T: de::DeserializeSeed<'de>>(self, _seed: T) -> Result<T::Value, Self::Error> {
Err(LuaError::Custom(format!(
"unimplemented wireplumber::lua::EnumDeserializer::newtype_variant_seed"
)))
}
fn tuple_variant<V: Visitor<'de>>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error> {
Err(LuaError::Custom(format!(
"unimplemented wireplumber::lua::EnumDeserializer::tuple_variant"
)))
}
fn struct_variant<V: Visitor<'de>>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Self::Error> {
Err(LuaError::Custom(format!(
"unimplemented wireplumber::lua::EnumDeserializer::struct_variant"
)))
}
}
#[repr(transparent)]
struct UnitEnumDeserializer<'v> {
de: Deserializer<'v>,
}
impl<'v> UnitEnumDeserializer<'v> {
fn new(de: Deserializer<'v>) -> Self {
Self { de }
}
}
impl<'v, 'de> de::EnumAccess<'de> for UnitEnumDeserializer<'v> {
type Error = LuaError;
type Variant = Self;
fn variant_seed<V: de::DeserializeSeed<'de>>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> {
let value = seed.deserialize(self.de.clone())?;
Ok((value, self))
}
}
impl<'v, 'de> de::VariantAccess<'de> for UnitEnumDeserializer<'v> {
type Error = LuaError;
fn unit_variant(self) -> Result<(), Self::Error> {
Ok(())
}
fn newtype_variant_seed<T: de::DeserializeSeed<'de>>(self, _seed: T) -> Result<T::Value, Self::Error> {
Err(self.de.unsupported())
}
fn tuple_variant<V: Visitor<'de>>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error> {
Err(self.de.unsupported())
}
fn struct_variant<V: Visitor<'de>>(
self,
_fields: &'static [&'static str],
_visitor: V,
) -> Result<V::Value, Self::Error> {
Err(self.de.unsupported())
}
}
struct SeqDeserializer<'v, I> {
de: Deserializer<'v>,
iter: I,
}
impl<'v, I> SeqDeserializer<'v, I> {
fn new(iter: I, de: Deserializer<'v>) -> Self {
Self { iter, de }
}
}
impl<'v, 'de, 'i, I: Iterator<Item = Option<LuaVariant<'i>>>> de::SeqAccess<'de> for SeqDeserializer<'v, I> {
type Error = LuaError;
fn next_element_seed<T: de::DeserializeSeed<'de>>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> {
self
.iter
.next()
.map(|v| seed.deserialize(self.de.change_variant(v.unwrap_or_else(|| LuaVariant::nil()))))
.transpose()
}
fn size_hint(&self) -> Option<usize> {
self.iter.size_hint().1
}
}
struct MapDeserializer<'v> {
de: Deserializer<'v>,
index: usize,
}
impl<'v> MapDeserializer<'v> {
fn new(de: Deserializer<'v>) -> Self {
Self { de, index: 0 }
}
fn table(&self) -> LuaTable {
self.de.variant.get_table().expect("MapDeserializer")
}
}
impl<'v, 'de> de::MapAccess<'de> for MapDeserializer<'v> {
type Error = LuaError;
fn next_key_seed<K: de::DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> {
let table = self.table();
if self.index >= table.entry_len() {
return Ok(None)
}
match table.key_at(self.index) {
Some(key) => seed.deserialize(key.into_deserializer()).map(Some),
None if !table.variant_is_dict() => seed.deserialize((self.index + 1).into_deserializer()).map(Some),
None => Ok(None),
}
}
fn next_value_seed<V: de::DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Self::Error> {
let value = self
.table()
.value_at(self.index)
.ok_or_else(|| -> LuaError { todo!() })?;
self.index += 1;
seed.deserialize(self.de.change_variant(value))
}
fn size_hint(&self) -> Option<usize> {
self.table().entry_len().checked_sub(self.index)
}
}
impl<'v> From<LuaVariant<'v>> for Deserializer<'v> {
fn from(v: LuaVariant<'v>) -> Self {
Self::new(v)
}
}
impl<'v> From<LuaTable<'v>> for Deserializer<'v> {
fn from(v: LuaTable<'v>) -> Self {
Self::new(v.into())
}
}