diff --git a/Cargo.lock b/Cargo.lock index cdecd0b..032e560 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -110,6 +110,7 @@ dependencies = [ "cstr-argument", "foreign-types", "nvpair-sys", + "serde", ] [[package]] @@ -255,6 +256,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "serde" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" + [[package]] name = "snafu" version = "0.6.10" diff --git a/nvpair/Cargo.toml b/nvpair/Cargo.toml index 69c3bc2..835d2cb 100644 --- a/nvpair/Cargo.toml +++ b/nvpair/Cargo.toml @@ -13,6 +13,7 @@ edition = "2018" cstr-argument = "0.1" nvpair-sys = { path = "../nvpair-sys", version = "0.4.0" } foreign-types = "0.5.0" +serde = "1.0" [badges] travis-ci = { repository = "jmesmon/rust-libzfs" } diff --git a/nvpair/src/de.rs b/nvpair/src/de.rs new file mode 100644 index 0000000..2b8d614 --- /dev/null +++ b/nvpair/src/de.rs @@ -0,0 +1,270 @@ +use crate::*; +use ::serde::de::{DeserializeSeed, MapAccess, SeqAccess, Visitor}; +use ::serde::{de, forward_to_deserialize_any, Deserialize}; +use serde::de::DeserializeOwned; +use std::ffi::CStr; +use std::marker::PhantomData; + +pub fn from_bytes(buf: &[u8]) -> Result +where + T: DeserializeOwned, +{ + from_nvlist(&NvList::try_unpack(buf)?) +} + +pub fn from_nvlist<'a, T>(s: &'a NvList) -> Result +where + T: Deserialize<'a>, +{ + let mut deserializer = Deserializer::from_nvlist(s); + let t = T::deserialize(&mut deserializer)?; + /* + match deserializer.iterator.next() { + Some(pair) => Err(Error::Message(format!( + "unconsumed nvpairs, including {:?}", + pair + ))), + None => Ok(t), + } + */ + Ok(t) +} + +#[derive(Debug)] +struct Deserializer<'de> { + iterator: NvListIter<'de>, + data: Option>, +} + +impl<'de> Deserializer<'de> { + fn from_nvlist(input: &'de NvListRef) -> Self { + Deserializer { + iterator: input.iter(), + data: None, + } + } +} + +impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_map(self) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +impl<'de> MapAccess<'de> for Deserializer<'de> { + type Error = Error; + + fn next_key_seed(&mut self, seed: K) -> Result> + where + K: DeserializeSeed<'de>, + { + let nvpair = match self.iterator.next() { + Some(nvpair) => nvpair, + None => return Ok(None), + }; + + let mut key_deserializer = KeyDeserializer { key: nvpair.name() }; + self.data = Some(nvpair.data()); + + seed.deserialize(&mut key_deserializer).map(Some) + } + + fn next_value_seed(&mut self, seed: V) -> Result + where + V: DeserializeSeed<'de>, + { + match self.data.take() { + Some(data) => { + let mut value_deserializer = ValueDeserializer { data }; + seed.deserialize(&mut value_deserializer) + } + None => Err(Error::Message("expected value but not present".to_string())), + } + } +} + +#[derive(Debug)] +struct KeyDeserializer<'de> { + key: &'de CStr, +} + +impl<'de, 'a> de::Deserializer<'de> for &'a mut KeyDeserializer<'de> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + visitor.visit_borrowed_str(self.key.to_str()?) + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +#[derive(Debug)] +struct ValueDeserializer<'de> { + data: NvData<'de>, +} + +impl<'de, 'a> de::Deserializer<'de> for &'a mut ValueDeserializer<'de> { + type Error = Error; + + fn deserialize_any(self, visitor: V) -> Result + where + V: Visitor<'de>, + { + match self.data { + NvData::Unknown => Err(Error::UnknownNvPairType), + NvData::Bool => visitor.visit_none(), + NvData::BoolV(v) => visitor.visit_bool(v), + NvData::Byte(v) => visitor.visit_u8(v), + NvData::Int8(v) => visitor.visit_i8(v), + NvData::Uint8(v) => visitor.visit_u8(v), + NvData::Int16(v) => visitor.visit_i16(v), + NvData::Uint16(v) => visitor.visit_u16(v), + NvData::Int32(v) => visitor.visit_i32(v), + NvData::Uint32(v) => visitor.visit_u32(v), + NvData::Int64(v) => visitor.visit_i64(v), + NvData::Uint64(v) => visitor.visit_u64(v), + NvData::Str(v) => visitor.visit_borrowed_str(v.to_str()?), + NvData::NvListRef(v) => visitor.visit_map(Deserializer::from_nvlist(v)), + NvData::ByteArray(v) => visitor.visit_borrowed_bytes(v), + NvData::Int8Array(v) => visitor.visit_seq(SeqAccessor::new(v.iter())), + NvData::Uint8Array(v) => visitor.visit_borrowed_bytes(v), + NvData::Int16Array(v) => visitor.visit_seq(SeqAccessor::new(v.iter())), + NvData::Uint16Array(v) => visitor.visit_seq(SeqAccessor::new(v.iter())), + NvData::Int32Array(v) => visitor.visit_seq(SeqAccessor::new(v.iter())), + NvData::Uint32Array(v) => visitor.visit_seq(SeqAccessor::new(v.iter())), + NvData::Int64Array(v) => visitor.visit_seq(SeqAccessor::new(v.iter())), + NvData::Uint64Array(v) => visitor.visit_seq(SeqAccessor::new(v.iter())), + NvData::NvListRefArray(_) => Err(Error::UnknownNvPairType), + } + } + + forward_to_deserialize_any! { + bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string + bytes byte_buf option unit unit_struct newtype_struct seq tuple + tuple_struct map struct enum identifier ignored_any + } +} + +#[derive(Debug)] +struct SeqAccessor<'de, I> +where + I: Iterator, + ::Item: Into>, +{ + iterator: I, + _phantom: std::marker::PhantomData<&'de I>, +} + +impl<'de, I> SeqAccessor<'de, I> +where + I: Iterator, + ::Item: Into>, +{ + fn new(iterator: I) -> Self { + Self { + iterator, + _phantom: PhantomData, + } + } +} + +impl<'de, I> SeqAccess<'de> for SeqAccessor<'de, I> +where + I: Iterator, + ::Item: Into>, +{ + type Error = Error; + + fn next_element_seed(&mut self, seed: K) -> Result> + where + K: DeserializeSeed<'de>, + { + let item = match self.iterator.next() { + Some(item) => item, + None => return Ok(None), + }; + + let mut vd = ValueDeserializer { data: item.into() }; + seed.deserialize(&mut vd).map(Some) + } +} + +impl From<&u64> for NvData<'_> { + fn from(v: &u64) -> Self { + NvData::Uint64(*v) + } +} + +impl From<&i64> for NvData<'_> { + fn from(v: &i64) -> Self { + NvData::Int64(*v) + } +} + +impl From<&u32> for NvData<'_> { + fn from(v: &u32) -> Self { + NvData::Uint32(*v) + } +} + +impl From<&i32> for NvData<'_> { + fn from(v: &i32) -> Self { + NvData::Int32(*v) + } +} + +impl From<&u16> for NvData<'_> { + fn from(v: &u16) -> Self { + NvData::Uint16(*v) + } +} + +impl From<&i16> for NvData<'_> { + fn from(v: &i16) -> Self { + NvData::Int16(*v) + } +} + +impl From<&u8> for NvData<'_> { + fn from(v: &u8) -> Self { + NvData::Uint8(*v) + } +} + +impl From<&i8> for NvData<'_> { + fn from(v: &i8) -> Self { + NvData::Int8(*v) + } +} + +/* +impl<'a> From<&'a NvListRef> for NvData<'a> { + fn from(v: &'a NvListRef) -> Self { + NvData::NvListRef(v) + } +} + +impl<'a> From<&&'a NvListRef> for NvData<'a> { + fn from(v: &&'a NvListRef) -> Self { + NvData::NvListRef(*v) + } +} +*/ diff --git a/nvpair/src/error.rs b/nvpair/src/error.rs new file mode 100644 index 0000000..811862d --- /dev/null +++ b/nvpair/src/error.rs @@ -0,0 +1,74 @@ +use ::serde::{de, ser}; +use std::ffi::NulError; +use std::fmt; +use std::fmt::Display; + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub enum Error { + Message(String), + UnknownNvPairType, + + // Zero or more variants that can be created directly by the Serializer and + // Deserializer without going through `ser::Error` and `de::Error`. These + // are specific to the format, in this case JSON. + //Eof, + NulError(NulError), + IoError(std::io::Error), + Utf8Error(std::str::Utf8Error), + /* + Syntax, + ExpectedBoolean, + ExpectedInteger, + ExpectedString, + ExpectedNull, + ExpectedArray, + ExpectedArrayComma, + ExpectedArrayEnd, + ExpectedMap, + ExpectedMapColon, + ExpectedMapComma, + ExpectedMapEnd, + ExpectedEnum, + TrailingCharacters, + */ +} + +impl ser::Error for Error { + fn custom(msg: T) -> Self { + Error::Message(msg.to_string()) + } +} + +impl de::Error for Error { + fn custom(msg: T) -> Self { + Error::Message(msg.to_string()) + } +} + +impl Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, formatter) + } +} + +impl From for Error { + fn from(e: NulError) -> Self { + Error::NulError(e) + } +} + +impl From for Error { + fn from(e: std::io::Error) -> Self { + Error::IoError(e) + } +} + +impl From for Error { + fn from(e: std::str::Utf8Error) -> Self { + Error::Utf8Error(e) + } +} + +impl std::error::Error for Error {} diff --git a/nvpair/src/lib.rs b/nvpair/src/lib.rs index b98849d..6f021a6 100644 --- a/nvpair/src/lib.rs +++ b/nvpair/src/lib.rs @@ -1,8 +1,19 @@ #![warn(missing_debug_implementations, rust_2018_idioms)] +mod de; +mod error; +mod ser; +pub use de::from_bytes; +pub use de::from_nvlist; +pub use error::Error; +pub use error::Result; +pub use ser::to_bytes; +pub use ser::to_nvlist; + use cstr_argument::CStrArgument; use foreign_types::{foreign_type, ForeignType, ForeignTypeRef, Opaque}; use nvpair_sys as sys; +use std::ffi::CString; use std::mem::MaybeUninit; use std::os::raw::c_int; use std::{ffi, fmt, io, ptr}; @@ -46,6 +57,39 @@ pub trait NvEncode { //fn read(NvPair &nv) -> io::Result; } +/* +impl NvEncode for NvData<'_> { + fn insert_into(&self, name: S, nv: &mut NvListRef) -> io::Result<()> { + match self { + NvData::Unknown => todo!(), + NvData::Bool => nv.add_boolean(name), + NvData::BoolV(v) => v.insert_into(name, nv), + NvData::Byte(v) => v.insert_into(name, nv), + NvData::Int8(v) => v.insert_into(name, nv), + NvData::Uint8(v) => v.insert_into(name, nv), + NvData::Int16(v) => v.insert_into(name, nv), + NvData::Uint16(v) => v.insert_into(name, nv), + NvData::Int32(v) => v.insert_into(name, nv), + NvData::Uint32(v) => v.insert_into(name, nv), + NvData::Int64(v) => v.insert_into(name, nv), + NvData::Uint64(v) => v.insert_into(name, nv), + NvData::Str(v) => v.insert_into(name, nv), + NvData::NvListRef(v) => v.insert_into(name, nv), + NvData::ByteArray(v) => v.insert_into(name, nv), + NvData::Int8Array(v) => v.insert_into(name, nv), + NvData::Uint8Array(v) => v.insert_into(name, nv), + NvData::Int16Array(v) => v.insert_into(name, nv), + NvData::Uint16Array(v) => v.insert_into(name, nv), + NvData::Int32Array(v) => v.insert_into(name, nv), + NvData::Uint32Array(v) => v.insert_into(name, nv), + NvData::Int64Array(v) => v.insert_into(name, nv), + NvData::Uint64Array(v) => v.insert_into(name, nv), + NvData::NvListRefArray(_v) => todo!(), + } + } +} +*/ + impl NvEncode for bool { fn insert_into(&self, name: S, nv: &mut NvListRef) -> io::Result<()> { let name = name.into_cstr(); diff --git a/nvpair/src/ser.rs b/nvpair/src/ser.rs new file mode 100644 index 0000000..36eeee4 --- /dev/null +++ b/nvpair/src/ser.rs @@ -0,0 +1,529 @@ +use crate::*; +use ::serde::{ser, Serialize}; +use std::ffi; + +#[derive(Debug)] +struct Serializer {} + +#[derive(Debug)] +enum NvDataOwned { + Unknown, + None, + Bool, + BoolV(bool), + Byte(u8), + Int8(i8), + Uint8(u8), + Int16(i16), + Uint16(u16), + Int32(i32), + Uint32(u32), + Int64(i64), + Uint64(u64), + String(CString), + NvList(NvList), + ByteArray(Vec), + Int8Array(Vec), + Uint8Array(Vec), + Int16Array(Vec), + Uint16Array(Vec), + Int32Array(Vec), + Uint32Array(Vec), + Int64Array(Vec), + Uint64Array(Vec), + NvListArray(Vec), + /* TODO: + pub const DATA_TYPE_STRING_ARRAY: Type = 17; + pub const DATA_TYPE_HRTIME: Type = 18; + pub const DATA_TYPE_BOOLEAN_ARRAY: Type = 24; + pub const DATA_TYPE_DOUBLE: Type = 27; + */ +} + +impl NvEncode for NvDataOwned { + fn insert_into(&self, name: S, nv: &mut NvListRef) -> io::Result<()> { + match self { + NvDataOwned::Unknown => todo!(), + NvDataOwned::None => Ok(()), // ignore None values + NvDataOwned::Bool => nv.add_boolean(name), + NvDataOwned::BoolV(v) => v.insert_into(name, nv), + NvDataOwned::Byte(v) => v.insert_into(name, nv), + NvDataOwned::Int8(v) => v.insert_into(name, nv), + NvDataOwned::Uint8(v) => v.insert_into(name, nv), + NvDataOwned::Int16(v) => v.insert_into(name, nv), + NvDataOwned::Uint16(v) => v.insert_into(name, nv), + NvDataOwned::Int32(v) => v.insert_into(name, nv), + NvDataOwned::Uint32(v) => v.insert_into(name, nv), + NvDataOwned::Int64(v) => v.insert_into(name, nv), + NvDataOwned::Uint64(v) => v.insert_into(name, nv), + NvDataOwned::String(v) => v.insert_into(name, nv), + NvDataOwned::NvList(v) => v.insert_into(name, nv), + NvDataOwned::ByteArray(v) => v.insert_into(name, nv), + NvDataOwned::Int8Array(v) => v.insert_into(name, nv), + NvDataOwned::Uint8Array(v) => v.insert_into(name, nv), + NvDataOwned::Int16Array(v) => v.insert_into(name, nv), + NvDataOwned::Uint16Array(v) => v.insert_into(name, nv), + NvDataOwned::Int32Array(v) => v.insert_into(name, nv), + NvDataOwned::Uint32Array(v) => v.insert_into(name, nv), + NvDataOwned::Int64Array(v) => v.insert_into(name, nv), + NvDataOwned::Uint64Array(v) => v.insert_into(name, nv), + NvDataOwned::NvListArray(_v) => todo!(), + } + } +} + +pub fn to_bytes(value: &T, code: NvEncoding) -> Result> +where + T: Serialize, +{ + Ok(to_nvlist(value)?.pack(code)?) +} + +pub fn to_nvlist(value: &T) -> Result +where + T: Serialize, +{ + let mut serializer = Serializer {}; + match value.serialize(&mut serializer)? { + NvDataOwned::NvList(v) => Ok(v), + _ => todo!(), + } +} + +impl<'a> ser::Serializer for &'a mut Serializer { + type Ok = NvDataOwned; + type Error = Error; + + type SerializeSeq = SeqSerializer<'a>; + type SerializeTuple = Self::SerializeSeq; + type SerializeTupleStruct = Self::SerializeSeq; + type SerializeTupleVariant = Self; + type SerializeMap = Self::SerializeStruct; + type SerializeStruct = StructSerializer<'a>; + type SerializeStructVariant = Self; + + fn serialize_bool(self, v: bool) -> Result { + Ok(NvDataOwned::BoolV(v)) + } + + fn serialize_i8(self, v: i8) -> Result { + Ok(NvDataOwned::Int8(v)) + } + + fn serialize_i16(self, v: i16) -> Result { + Ok(NvDataOwned::Int16(v)) + } + + fn serialize_i32(self, v: i32) -> Result { + Ok(NvDataOwned::Int32(v)) + } + + fn serialize_i64(self, v: i64) -> Result { + Ok(NvDataOwned::Int64(v)) + } + + fn serialize_u8(self, v: u8) -> Result { + Ok(NvDataOwned::Uint8(v)) + } + + fn serialize_u16(self, v: u16) -> Result { + Ok(NvDataOwned::Uint16(v)) + } + + fn serialize_u32(self, v: u32) -> Result { + Ok(NvDataOwned::Uint32(v)) + } + + fn serialize_u64(self, v: u64) -> Result { + Ok(NvDataOwned::Uint64(v)) + } + + fn serialize_f32(self, v: f32) -> Result { + self.serialize_f64(f64::from(v)) + } + + fn serialize_f64(self, v: f64) -> Result { + todo!() + } + + fn serialize_char(self, v: char) -> Result { + Ok(NvDataOwned::String(ffi::CString::new(v.to_string())?)) + } + + fn serialize_str(self, v: &str) -> Result { + Ok(NvDataOwned::String(ffi::CString::new(v)?)) + } + + fn serialize_bytes(self, v: &[u8]) -> Result { + // XXX copying around a potentially big buffer + Ok(NvDataOwned::ByteArray(v.to_owned())) + } + + fn serialize_none(self) -> Result { + // This member will be ignored + Ok(NvDataOwned::None) + } + + fn serialize_some(self, value: &T) -> Result + where + T: Serialize, + { + // transparent + value.serialize(self) + } + + fn serialize_unit(self) -> Result { + // Note: Option<()> will serialize to either not present, or nvlist_add_boolean(). + Ok(NvDataOwned::Bool) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.serialize_unit() + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + self.serialize_str(variant) + } + + fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result + where + T: Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: Serialize, + { + let mut nvl = NvList::new_unique_names(); + nvl.insert(variant, &value.serialize(self)?)?; + Ok(NvDataOwned::NvList(nvl)) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(SeqSerializer::new(self, len)) + } + + fn serialize_tuple(self, len: usize) -> Result { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + // XXX SeqSerializer requires that they be the same type (it turns into + // nvlist_insert_*_array()), so maybe we should serialize as nvlist with + // keys "0", "1", "2", etc. + todo!() + } + + fn serialize_tuple_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + todo!() + } + + fn serialize_map(self, _len: Option) -> Result { + Ok(StructSerializer::new(self)) + } + + fn serialize_struct(self, _name: &'static str, _len: usize) -> Result { + // name of the struct is ignored + Ok(StructSerializer::new(self)) + } + + fn serialize_struct_variant( + self, + name: &'static str, + variant_index: u32, + variant: &'static str, + len: usize, + ) -> Result { + todo!() + } +} + +impl<'a> ser::SerializeTupleVariant for &'a mut Serializer { + type Ok = NvDataOwned; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + todo!() + } + + fn end(self) -> Result { + todo!() + } +} + +impl<'a> ser::SerializeStructVariant for &'a mut Serializer { + type Ok = NvDataOwned; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + todo!() + } + + fn end(self) -> Result { + todo!() + } +} + +#[derive(Debug)] +struct StructSerializer<'a> { + serializer: &'a mut Serializer, + nvl: NvList, +} + +impl<'a> StructSerializer<'a> { + fn new(serializer: &'a mut Serializer) -> Self { + StructSerializer { + serializer, + nvl: NvList::new_unique_names(), + } + } +} + +impl<'a> ser::SerializeStruct for StructSerializer<'a> { + type Ok = NvDataOwned; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where + T: Serialize, + { + let data = value.serialize(&mut *self.serializer)?; + self.nvl.insert(key, &data)?; + Ok(()) + } + + fn end(self) -> Result { + Ok(NvDataOwned::NvList(self.nvl)) + } +} + +impl<'a> ser::SerializeMap for StructSerializer<'a> { + type Ok = NvDataOwned; + type Error = Error; + + fn end(self) -> Result { + Ok(NvDataOwned::NvList(self.nvl)) + } + + fn serialize_key(&mut self, _key: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(Error::Message( + "map must have whole entry available at once".to_string(), + )) + } + + fn serialize_value(&mut self, _value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + Err(Error::Message( + "map must have whole entry available at once".to_string(), + )) + } + + fn serialize_entry(&mut self, key: &K, value: &V) -> Result<()> + where + K: ?Sized + Serialize, + V: ?Sized + Serialize, + { + let key_owned: NvDataOwned = key.serialize(&mut *self.serializer)?; + let key_string = match key_owned { + NvDataOwned::String(v) => v, + other => { + return Err(Error::Message(format!( + "map keys must be strings, not {:?}", + other + ))) + } + }; + + let data = value.serialize(&mut *self.serializer)?; + self.nvl.insert(key_string, &data)?; + Ok(()) + } +} + +#[derive(Debug)] +struct SeqSerializer<'a> { + serializer: &'a mut Serializer, + vec: Vec, +} + +impl<'a> SeqSerializer<'a> { + fn new(serializer: &'a mut Serializer, len: Option) -> Self { + SeqSerializer { + serializer, + vec: Vec::with_capacity(len.unwrap_or(0)), + } + } +} + +impl<'a> ser::SerializeTuple for SeqSerializer<'a> { + type Ok = NvDataOwned; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + ser::SerializeSeq::end(self) + } +} + +impl<'a> ser::SerializeTupleStruct for SeqSerializer<'a> { + type Ok = NvDataOwned; + type Error = Error; + + fn serialize_field(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result { + ser::SerializeSeq::end(self) + } +} + +impl<'a> ser::SerializeSeq for SeqSerializer<'a> { + type Ok = NvDataOwned; + type Error = Error; + + fn serialize_element(&mut self, value: &T) -> Result<()> + where + T: ?Sized + Serialize, + { + let data = value.serialize(&mut *self.serializer)?; + self.vec.push(data); + Ok(()) + } + + fn end(self) -> Result { + if self.vec.is_empty() { + return Err(Error::Message( + "zero-length (untyped) sequences not supported".to_string(), + )); + } + match self.vec[0] { + NvDataOwned::Unknown => Err(Error::Message( + "sequence of unknown not supported".to_string(), + )), + NvDataOwned::None => todo!(), + NvDataOwned::Bool => Err(Error::Message( + "sequence of (value-less) bool not supported".to_string(), + )), + NvDataOwned::BoolV(_) => todo!(), + NvDataOwned::Byte(_) => { + let mut vec = Vec::with_capacity(self.vec.len()); + let len = self.vec.len(); + let mut iter = self.vec.into_iter(); + while let Some(NvDataOwned::Byte(v)) = iter.next() { + vec.push(v); + } + if vec.len() == len { + Ok(NvDataOwned::ByteArray(vec)) + } else { + Err(Error::Message( + "hetrogenious sequences not supported".to_string(), + )) + } + } + NvDataOwned::Int8(_) => { + todo!() + } + NvDataOwned::Uint8(_) => { + todo!() + } + NvDataOwned::Int16(_) => { + todo!() + } + NvDataOwned::Uint16(_) => todo!(), + NvDataOwned::Int32(_) => todo!(), + NvDataOwned::Uint32(_) => todo!(), + NvDataOwned::Int64(_) => todo!(), + NvDataOwned::Uint64(_) => todo!(), + NvDataOwned::String(_) => todo!(), + NvDataOwned::NvList(_) => { + let mut vec = Vec::with_capacity(self.vec.len()); + let len = self.vec.len(); + let mut iter = self.vec.into_iter(); + while let Some(NvDataOwned::NvList(v)) = iter.next() { + vec.push(v); + } + if vec.len() == len { + Ok(NvDataOwned::NvListArray(vec)) + } else { + Err(Error::Message( + "hetrogenious sequences not supported".to_string(), + )) + } + } + NvDataOwned::ByteArray(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::Int8Array(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::Uint8Array(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::Int16Array(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::Uint16Array(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::Int32Array(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::Uint32Array(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::Int64Array(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::Uint64Array(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + NvDataOwned::NvListArray(_) => Err(Error::Message( + "sequence of sequence not supported".to_string(), + )), + } + } +}