diff --git a/lib/tmp/Cargo.toml b/lib/tmp/Cargo.toml index d6c949b..0ac46f6 100644 --- a/lib/tmp/Cargo.toml +++ b/lib/tmp/Cargo.toml @@ -19,6 +19,9 @@ readme.workspace = true repository.workspace = true rust-version.workspace = true +[features] +polonius = [] + [dependencies] osi = { workspace = true } sys = { workspace = true } diff --git a/lib/tmp/src/fmt/dbus/dvar.rs b/lib/tmp/src/fmt/dbus/dvar.rs new file mode 100644 index 0000000..a7df98c --- /dev/null +++ b/lib/tmp/src/fmt/dbus/dvar.rs @@ -0,0 +1,820 @@ +//! # D-Bus DVariant Format +//! +//! This implements the wire encoding of the original D-Bus specification +//! (v0.43 and later). It provides encoders and decoders for memory mapped +//! data. +//! +//! ## Deviations +//! +//! The following behavior deviates from the D-Bus Specification v0.43: +//! +//! - The length of the encoded data can be up to `isize::MAX`. That is, +//! anything that can be mapped into the address space can be decoded and +//! encoded. No arbitrary limits are enforced. +//! - The nesting depth of compound types is not limited. The length of the +//! type signature naturally limits the nesting depth. No additional limits +//! are enforced. +//! - All operations run in O(n) space and time relative to the length of the +//! encoded data (data length includes the type signature). If the caller +//! needs stricter limits, they must enforce it manually. +//! - Embedded 0 bytes are supported for strings and objects. They do not get +//! any special treatment. + +use alloc::{sync, vec}; +use core::ops::ControlFlow as Flow; + +use crate::fmt::dbus; +use crate::io; + +#[derive(Clone, Copy, Debug, Hash)] +#[derive(Eq, Ord, PartialEq, PartialOrd)] +pub enum Format { + DVarBe, + DVarLe, +} + +#[derive(Clone)] +struct Level { + idx: usize, + from: usize, + meta: usize, +} + +type MownSig<'sig> = osi::mown::Mown<'sig, dbus::Sig, sync::Arc>; +type Cursor<'sig> = dbus::Cursor<'sig, sync::Arc>; + +pub struct Enc<'sig, 'write> { + done: bool, + format: Format, + cursor: Cursor<'sig>, + level: Level, + stack: vec::Vec<(dbus::Element, Level, Option>)>, + write: &'write mut dyn io::map::Write, + enc: Option<(&'write mut Level, Option, &'write mut usize)>, +} + +pub struct Dec<'sig, 'read> { + format: Format, + cursor: Cursor<'sig>, + level: Level, + stack: vec::Vec<(dbus::Element, Level, Option>)>, + read: &'read mut dyn io::map::Read, + dec: Option<(&'read mut Level, Option, &'read mut usize)>, +} + +impl core::convert::From for dbus::Error { + fn from(v: io::map::Error) -> Self { + Self::Io(v) + } +} + +impl Format { + fn is_be(&self) -> bool { + match *self { + Format::DVarBe => true, + Format::DVarLe => false, + } + } + + fn u8(&self, v: u8) -> [u8; 1] { + [v] + } + + fn u16(&self, v: u16) -> [u8; 2] { + if self.is_be() { v.to_be_bytes() } else { v.to_le_bytes() } + } + + fn u32(&self, v: u32) -> [u8; 4] { + if self.is_be() { v.to_be_bytes() } else { v.to_le_bytes() } + } + + fn u64(&self, v: u64) -> [u8; 8] { + if self.is_be() { v.to_be_bytes() } else { v.to_le_bytes() } + } + + fn to_u8(&self, v: [u8; 1]) -> u8 { + if self.is_be() { u8::from_be_bytes(v) } else { u8::from_le_bytes(v) } + } + + fn to_u16(&self, v: [u8; 2]) -> u16 { + if self.is_be() { u16::from_be_bytes(v) } else { u16::from_le_bytes(v) } + } + + fn to_u32(&self, v: [u8; 4]) -> u32 { + if self.is_be() { u32::from_be_bytes(v) } else { u32::from_le_bytes(v) } + } +} + +impl<'sig, 'write> Enc<'sig, 'write> { + pub fn with( + sig: MownSig<'sig>, + format: Format, + write: &'write mut dyn io::map::Write, + ) -> Self { + Self { + done: false, + cursor: dbus::Cursor::new(sig), + format: format, + level: Level { + idx: 0, + from: 0, + meta: 0, + }, + stack: vec::Vec::new(), + write: write, + enc: None, + } + } + + pub fn new_be( + sig: &'sig dbus::Sig, + write: &'write mut dyn io::map::Write, + ) -> Self { + Self::with(MownSig::new_borrowed(sig), Format::DVarBe, write) + } + + pub fn new_le( + sig: &'sig dbus::Sig, + write: &'write mut dyn io::map::Write, + ) -> Self { + Self::with(MownSig::new_borrowed(sig), Format::DVarLe, write) + } + + pub fn enc(&mut self) -> Result, dbus::Error> { + let up_step = self.cursor.idx_step(); + let (up_sig, up_idx) = self.cursor.raw(); + + if let Some(v) = up_sig.at(*up_idx) { + Ok(Enc { + done: false, + cursor: Cursor::new_borrowed(v), + format: self.format, + level: Level { + idx: self.level.idx, + from: self.level.idx, + meta: self.level.idx, + }, + stack: vec::Vec::new(), + write: self.write, + enc: Some((&mut self.level, up_step, up_idx)), + }) + } else { + Err(dbus::Error::Mismatch) + } + } + + pub fn enc_with(&mut self, sig: MownSig) -> Result, dbus::Error> { + let (cursor_sig, cursor_idx) = self.cursor.raw(); + + if Some(&*sig) == cursor_sig.at(*cursor_idx) { + self.enc() + } else { + Err(dbus::Error::Mismatch) + } + } + + pub fn commit(&mut self) -> Result<(), dbus::Error> { + if self.cursor.idx_step().is_some() || !self.stack.is_empty() { + return Err(dbus::Error::Pending); + } + + if let Some((up_level, up_step, up_idx)) = self.enc.take() { + up_level.idx = self.level.idx; + if let Some(v) = up_step { + *up_idx = v; + } + self.done = true; + } else if !self.done { + unsafe { self.write.commit(self.level.idx) }; + self.done = true; + } + + Ok(()) + } + + fn write( + write: &mut dyn io::map::Write, + idx: &mut usize, + data: &[u8], + ) -> Flow> { + write.write(idx, data).map_break(|v| v.map(|v| v.into())) + } + + fn write_iter( + write: &mut dyn io::map::Write, + idx: &mut usize, + data: &mut dyn ExactSizeIterator, + ) -> Flow> { + write.write_iter(idx, data).map_break(|v| v.map(|v| v.into())) + } + + fn zero( + write: &mut dyn io::map::Write, + idx: &mut usize, + len: usize, + ) -> Flow> { + write.zero(idx, len).map_break(|v| v.map(|v| v.into())) + } + + fn align( + write: &mut dyn io::map::Write, + idx: &mut usize, + exp: u8, + ) -> Flow> { + write.align_exp2(idx, exp).map_break(|v| v.map(|v| v.into())) + } + + fn fixed( + &mut self, + element: dbus::Element, + data: &[u8], + ) -> Flow, &mut Self> { + if self.cursor.element() != Some(element) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + + let mut idx = self.level.idx; + Self::align(self.write, &mut idx, element.dvar_alignment_exp())?; + Self::write(self.write, &mut idx, data)?; + self.level.idx = idx; + self.cursor.move_step(); + + Flow::Continue(self) + } + + fn str8( + &mut self, + element: dbus::Element, + data: &str, + ) -> Flow, &mut Self> { + if self.cursor.element() != Some(element) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + let Ok(n): Result = data.len().try_into() else { + return Flow::Break(Some(dbus::Error::DataOverflow)); + }; + + let mut idx = self.level.idx; + Self::align(self.write, &mut idx, dbus::Element::U8.dvar_alignment_exp())?; + Self::write(self.write, &mut idx, &self.format.u8(n))?; + Self::write(self.write, &mut idx, data.as_bytes())?; + Self::zero(self.write, &mut idx, 1)?; + self.level.idx = idx; + self.cursor.move_step(); + + Flow::Continue(self) + } + + fn str32( + &mut self, + element: dbus::Element, + data: &str, + ) -> Flow, &mut Self> { + if self.cursor.element() != Some(element) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + let Ok(n): Result = data.len().try_into() else { + return Flow::Break(Some(dbus::Error::DataOverflow)); + }; + + let mut idx = self.level.idx; + Self::align(self.write, &mut idx, dbus::Element::U32.dvar_alignment_exp())?; + Self::write(self.write, &mut idx, &self.format.u32(n))?; + Self::write(self.write, &mut idx, data.as_bytes())?; + Self::zero(self.write, &mut idx, 1)?; + self.level.idx = idx; + self.cursor.move_step(); + + Flow::Continue(self) + } + + pub fn u16(&mut self, data: u16) -> Flow, &mut Self> { + self.fixed(dbus::Element::U16, &self.format.u16(data)) + } + + pub fn u32(&mut self, data: u32) -> Flow, &mut Self> { + self.fixed(dbus::Element::U32, &self.format.u32(data)) + } + + pub fn u64(&mut self, data: u64) -> Flow, &mut Self> { + self.fixed(dbus::Element::U64, &self.format.u64(data)) + } + + pub fn string(&mut self, data: &str) -> Flow, &mut Self> { + self.str32(dbus::Element::String, data) + } + + pub fn object(&mut self, data: &str) -> Flow, &mut Self> { + self.str32(dbus::Element::Object, data) + } + + pub fn signature(&mut self, data: &str) -> Flow, &mut Self> { + self.str8(dbus::Element::Signature, data) + } + + pub fn variant_with( + &mut self, + sig: osi::mown::Mown<'sig, dbus::Sig, sync::Arc>, + ) -> Flow, &mut Self> { + if self.cursor.element() != Some(dbus::Element::Variant) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + let Ok(n): Result = sig.len().try_into() else { + return Flow::Break(Some(dbus::Error::DataOverflow)); + }; + + let mut level = self.level.clone(); + Self::align(self.write, &mut level.idx, dbus::Element::U8.dvar_alignment_exp())?; + Self::write(self.write, &mut level.idx, &self.format.u8(n))?; + Self::write_iter(self.write, &mut level.idx, &mut sig.into_iter().map(|v| v.code()))?; + Self::zero(self.write, &mut level.idx, 1)?; + level.meta = level.idx; + level.from = level.idx; + + let mut cursor = Cursor::new(sig); + core::mem::swap(&mut cursor, &mut self.cursor); + core::mem::swap(&mut level, &mut self.level); + self.stack.push((dbus::Element::Variant, level, Some(cursor))); + + Flow::Continue(self) + } + + pub fn variant(&mut self, sig: &'sig dbus::Sig) -> Flow, &mut Self> { + self.variant_with(osi::mown::Mown::new_borrowed(sig)) + } + + pub fn array(&mut self) -> Flow, &mut Self> { + if self.cursor.element() != Some(dbus::Element::Array) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + + let mut level = self.level.clone(); + let align = self.cursor.down().unwrap().dvar_alignment_exp(); + Self::align(self.write, &mut level.idx, dbus::Element::U32.dvar_alignment_exp())?; + level.meta = level.idx; + Self::write(self.write, &mut level.idx, &self.format.u32(0))?; + Self::align(self.write, &mut level.idx, align)?; + level.from = level.idx; + + core::mem::swap(&mut level, &mut self.level); + self.stack.push((dbus::Element::Array, level, None)); + self.cursor.move_down(); + + Flow::Continue(self) + } + + // NB: The related element is usually referred to as `struct`, yet that + // is a reserved keyword in Rust, hence this uses `structure`. + pub fn structure(&mut self) -> Flow, &mut Self> { + if self.cursor.element() != Some(dbus::Element::StructOpen) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + + let mut level = self.level.clone(); + let align = self.cursor.dvar_alignment_exp().unwrap(); + Self::align(self.write, &mut level.idx, align)?; + level.meta = level.idx; + level.from = level.idx; + + core::mem::swap(&mut level, &mut self.level); + self.stack.push((dbus::Element::StructOpen, level, None)); + self.cursor.move_down(); + + Flow::Continue(self) + } + + pub fn dict(&mut self) -> Flow, &mut Self> { + if self.cursor.element() != Some(dbus::Element::DictOpen) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + + let mut level = self.level.clone(); + let align = self.cursor.dvar_alignment_exp().unwrap(); + Self::align(self.write, &mut level.idx, align)?; + level.meta = level.idx; + level.from = level.idx; + + core::mem::swap(&mut level, &mut self.level); + self.stack.push((dbus::Element::DictOpen, level, None)); + self.cursor.move_down(); + + Flow::Continue(self) + } + + pub fn close(&mut self) -> Flow, &mut Self> { + if self.cursor.idx_step().is_some() { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + let Some( + &mut (up_element, ref mut up_level, ref mut up_cursor) + ) = self.stack.last_mut() else { + return Flow::Break(Some(dbus::Error::Mismatch)); + }; + + match up_element { + dbus::Element::Variant => { + // Nothing to finalize. + }, + dbus::Element::Array => { + let n = self.level.idx.strict_sub(self.level.from); + if n > 0 { + let Ok(n): Result = n.try_into() else { + return Flow::Break(Some(dbus::Error::DataOverflow)); + }; + let mut idx = self.level.meta; + Self::write(self.write, &mut idx, &self.format.u32(n))?; + } + }, + dbus::Element::StructOpen => { + // Nothing to finalize for structures. + }, + dbus::Element::DictOpen => { + // Nothing to finalize for structures. + }, + _ => core::unreachable!(), + } + + core::mem::swap(&mut self.level, up_level); + self.level.idx = up_level.idx; + + if let Some(ref mut v) = up_cursor { + core::mem::swap(v, &mut self.cursor); + } else { + self.cursor.move_up(); + } + + self.cursor.move_step(); + self.stack.pop(); + + Flow::Continue(self) + } +} + +impl<'sig, 'read> Dec<'sig, 'read> { + pub fn with( + sig: MownSig<'sig>, + format: Format, + read: &'read mut dyn io::map::Read, + ) -> Self { + Self { + cursor: dbus::Cursor::new(sig), + format: format, + level: Level { + idx: 0, + from: 0, + meta: 0, + }, + stack: vec::Vec::new(), + read: read, + dec: None, + } + } + + pub fn new_be( + sig: &'sig dbus::Sig, + read: &'read mut dyn io::map::Read, + ) -> Self { + Self::with(MownSig::new_borrowed(sig), Format::DVarBe, read) + } + + pub fn new_le( + sig: &'sig dbus::Sig, + read: &'read mut dyn io::map::Read, + ) -> Self { + Self::with(MownSig::new_borrowed(sig), Format::DVarLe, read) + } + + pub fn more(&self) -> bool { + self.level.idx < self.level.meta + } + + pub fn dec(&mut self) -> Result, dbus::Error> { + let up_step = self.cursor.idx_step(); + let (up_sig, up_idx) = self.cursor.raw(); + + if let Some(v) = up_sig.at(*up_idx) { + Ok(Dec { + cursor: Cursor::new_borrowed(v), + format: self.format, + level: Level { + idx: self.level.idx, + from: self.level.idx, + meta: self.level.idx, + }, + stack: vec::Vec::new(), + read: self.read, + dec: Some((&mut self.level, up_step, up_idx)), + }) + } else { + Err(dbus::Error::Mismatch) + } + } + + pub fn dec_with(&mut self, sig: MownSig) -> Result, dbus::Error> { + let (cursor_sig, cursor_idx) = self.cursor.raw(); + + if Some(&*sig) == cursor_sig.at(*cursor_idx) { + self.dec() + } else { + Err(dbus::Error::Mismatch) + } + } + + pub fn commit(&mut self) -> Result<(), dbus::Error> { + if self.cursor.idx_step().is_some() || !self.stack.is_empty() { + return Err(dbus::Error::Pending); + } + + if let Some((up_level, up_step, up_idx)) = self.dec.take() { + up_level.idx = self.level.idx; + if let Some(v) = up_step { + *up_idx = v; + } + } + + Ok(()) + } + + fn read( + read: &mut dyn io::map::Read, + idx: &mut usize, + data: &mut [u8], + ) -> Flow> { + read.read(idx, data).map_break(|v| v.map(|v| v.into())) + } + + fn read_uninit( + read: &mut dyn io::map::Read, + idx: &mut usize, + data: &mut [core::mem::MaybeUninit], + ) -> Flow> { + read.read_uninit(idx, data).map_break(|v| v.map(|v| v.into())) + } + + fn align( + _read: &mut dyn io::map::Read, + idx: &mut usize, + exp: u8, + ) -> Flow> { + match idx.checked_next_multiple_of((1 << exp) as usize) { + None => Flow::Break(Some(dbus::Error::Io(io::map::Error::Overflow))), + Some(v) => { + *idx = v; + Flow::Continue(()) + }, + } + } + + fn fixed( + &mut self, + element: dbus::Element, + data: &mut [u8], + ) -> Flow, &mut Self> { + if self.cursor.element() != Some(element) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + + let mut idx = self.level.idx; + Self::align(self.read, &mut idx, element.dvar_alignment_exp())?; + Self::read(self.read, &mut idx, data)?; + self.level.idx = idx; + self.cursor.move_step(); + + Flow::Continue(self) + } + + fn str8( + &mut self, + element: dbus::Element, + data: &mut alloc::string::String, + ) -> Flow, &mut Self> { + if self.cursor.element() != Some(element) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + + let mut idx = self.level.idx; + + // Read length byte. + let mut len_u = [0; _]; + Self::align(self.read, &mut idx, dbus::Element::U8.dvar_alignment_exp())?; + Self::read(self.read, &mut idx, &mut len_u)?; + let len = self.format.to_u8(len_u) as usize; + + // Read the string. + let mut buffer = alloc::vec::Vec::with_capacity(len); + let buf_p = &mut buffer.spare_capacity_mut()[..len]; + Self::read_uninit(self.read, &mut idx, buf_p)?; + // SAFETY: `Self::read_uninit()` always initializes the full slice. + unsafe { buffer.set_len(len) }; + + // Validate UTF-8. + *data = match alloc::string::String::from_utf8(buffer) { + Ok(v) => v, + Err(_) => return Flow::Break(Some(dbus::Error::DataNonUtf8)), + }; + + // Skip unused terminating 0. + idx = idx.strict_add(1); + + self.level.idx = idx; + self.cursor.move_step(); + + Flow::Continue(self) + } + + fn str32( + &mut self, + element: dbus::Element, + data: &mut alloc::string::String, + ) -> Flow, &mut Self> { + if self.cursor.element() != Some(element) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + + let mut idx = self.level.idx; + + // Read length byte. + let mut len_u = [0; _]; + Self::align(self.read, &mut idx, dbus::Element::U32.dvar_alignment_exp())?; + Self::read(self.read, &mut idx, &mut len_u)?; + let len = self.format.to_u32(len_u) as usize; + + // Read the string. + let mut buffer = alloc::vec::Vec::with_capacity(len); + let buf_p = &mut buffer.spare_capacity_mut()[..len]; + Self::read_uninit(self.read, &mut idx, buf_p)?; + // SAFETY: `Self::read_uninit()` always initializes the full slice. + unsafe { buffer.set_len(len) }; + + // Validate UTF-8. + *data = match alloc::string::String::from_utf8(buffer) { + Ok(v) => v, + Err(_) => return Flow::Break(Some(dbus::Error::DataNonUtf8)), + }; + + // Skip unused terminating 0. + idx = idx.strict_add(1); + + self.level.idx = idx; + self.cursor.move_step(); + + Flow::Continue(self) + } + + pub fn u16(&mut self, data: &mut u16) -> Flow, &mut Self> { + let mut v = [0; _]; + self.fixed(dbus::Element::U16, &mut v)?; + *data = self.format.to_u16(v); + Flow::Continue(self) + } + + pub fn string(&mut self, data: &mut alloc::string::String) -> Flow, &mut Self> { + self.str32(dbus::Element::String, data) + } + + pub fn signature(&mut self, data: &mut alloc::string::String) -> Flow, &mut Self> { + self.str8(dbus::Element::Signature, data) + } + + pub fn array(&mut self) -> Flow, &mut Self> { + if self.cursor.element() != Some(dbus::Element::Array) { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + + let mut level = self.level.clone(); + let align = self.cursor.down().unwrap().dvar_alignment_exp(); + + let mut len_u = [0; _]; + Self::align(self.read, &mut level.idx, dbus::Element::U32.dvar_alignment_exp())?; + Self::read(self.read, &mut level.idx, &mut len_u)?; + level.meta = self.format.to_u32(len_u) as usize; + Self::align(self.read, &mut level.idx, align)?; + + core::mem::swap(&mut level, &mut self.level); + self.stack.push((dbus::Element::Array, level, None)); + self.cursor.move_down(); + + Flow::Continue(self) + } + + pub fn close(&mut self) -> Flow, &mut Self> { + if self.cursor.idx_step().is_some() { + return Flow::Break(Some(dbus::Error::Mismatch)); + } + let Some( + &mut (up_element, ref mut up_level, ref mut up_cursor) + ) = self.stack.last_mut() else { + return Flow::Break(Some(dbus::Error::Mismatch)); + }; + + match up_element { + dbus::Element::Variant => { + // Nothing to finalize. + }, + dbus::Element::Array => { + // Nothing to finalize. + }, + dbus::Element::StructOpen => { + // Nothing to finalize for structures. + }, + dbus::Element::DictOpen => { + // Nothing to finalize for structures. + }, + _ => core::unreachable!(), + } + + core::mem::swap(&mut self.level, up_level); + self.level.idx = up_level.idx; + + if let Some(ref mut v) = up_cursor { + core::mem::swap(v, &mut self.cursor); + } else { + self.cursor.move_up(); + } + + self.cursor.move_step(); + self.stack.pop(); + + Flow::Continue(self) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn basic() { + { + let mut buf = vec::Vec::new(); + let mut enc = Enc::new_le(dbus::sig!(b"as"), &mut buf); + enc.array().continue_value().unwrap() + .string("foo").continue_value().unwrap() + .string("bar").continue_value().unwrap() + .close().continue_value().unwrap() + .commit().unwrap(); + + assert_eq!(buf, b"\ + \x10\0\0\0\ + \x03\0\0\0foo\0\ + \x03\0\0\0bar\0\ + "); + } + + { + let mut buf = vec::Vec::new(); + let mut enc = Enc::new_le(dbus::sig!(b"a{sv}"), &mut buf); + enc.array().continue_value().unwrap() + .dict().continue_value().unwrap() + .string("foo").continue_value().unwrap() + .variant(dbus::sig!(b"s")).continue_value().unwrap() + .string("bar").continue_value().unwrap() + .close().continue_value().unwrap() + .close().continue_value().unwrap() + .close().continue_value().unwrap() + .commit().unwrap(); + + assert_eq!(buf, b"\ + \x14\0\0\0\ + \0\0\0\0\ + \x03\0\0\0\ + foo\0\ + \x01s\0\0\ + \x03\0\0\0\ + bar\0\ + "); + } + + { + let mut buf = vec::Vec::new(); + let mut enc = Enc::new_le(dbus::sig!(b"as"), &mut buf); + { + let mut sub0 = enc.enc_with(dbus::sig!(b"as").into()).unwrap(); + sub0.array().continue_value().unwrap(); + { + let mut sub1 = sub0.enc().unwrap(); + sub1.string("000").continue_value().unwrap(); + sub1.commit().unwrap(); + } + { + let mut sub2 = sub0.enc().unwrap(); + sub2.string("001").continue_value().unwrap(); + sub2.commit().unwrap(); + } + sub0.string("002").continue_value().unwrap() + .string("003").continue_value().unwrap(); + sub0.close().continue_value().unwrap(); + sub0.commit().unwrap(); + } + enc.commit().unwrap(); + + assert_eq!(buf, b"\ + \x20\0\0\0\ + \x03\0\0\0000\0\ + \x03\0\0\0001\0\ + \x03\0\0\0002\0\ + \x03\0\0\0003\0\ + "); + } + } +} diff --git a/lib/tmp/src/fmt/dbus/ende.rs b/lib/tmp/src/fmt/dbus/ende.rs new file mode 100644 index 0000000..eb4021f --- /dev/null +++ b/lib/tmp/src/fmt/dbus/ende.rs @@ -0,0 +1,96 @@ +//! # D-Bus Encoders and Decoders + +use core::ops::ControlFlow as Flow; + +use crate::fmt::dbus; +use crate::io; + +#[derive(Clone, Copy, Debug, Hash)] +#[derive(Eq, Ord, PartialEq, PartialOrd)] +#[non_exhaustive] +pub enum Format { + DVarBe, + DVarLe, + Json, +} + +pub enum Enc<'sig, 'write> { + DVar(dbus::dvar::Enc<'sig, 'write>), +} + +pub enum Dec<'sig, 'write> { + DVar(dbus::dvar::Dec<'sig, 'write>), +} + +impl<'sig, 'write> Enc<'sig, 'write> { + pub fn new( + sig: &'sig dbus::Sig, + format: Format, + write: &'write mut dyn io::map::Write, + ) -> Self { + match format { + Format::DVarBe => Self::DVar( + dbus::dvar::Enc::new_be(sig, write), + ), + Format::DVarLe => Self::DVar( + dbus::dvar::Enc::new_le(sig, write), + ), + _ => core::unreachable!(), + } + } + + pub fn inline( + &mut self, + sig: &dbus::Sig, + dec: &mut Dec, + ) -> Flow> { + let mut cur = sig.cursor(); + + loop { + if dec.more() { + match cur.element().unwrap() { + _ => core::unreachable!(), + } + } else if let Some(idx) = cur.idx_up() { + dec.close()?; + cur.move_to(idx); + } else { + break; + } + } + + Flow::Continue(()) + } +} + +impl<'sig, 'read> Dec<'sig, 'read> { + pub fn new( + sig: &'sig dbus::Sig, + format: Format, + read: &'read mut dyn io::map::Read, + ) -> Self { + match format { + Format::DVarBe => Self::DVar( + dbus::dvar::Dec::new_be(sig, read), + ), + Format::DVarLe => Self::DVar( + dbus::dvar::Dec::new_le(sig, read), + ), + _ => core::unreachable!(), + } + } + + pub fn more(&self) -> bool { + match *self { + Self::DVar(ref v) => v.more(), + } + } + + pub fn close(&mut self) -> Flow> { + match *self { + Self::DVar(ref mut v) => v.close()?, + }; + + Flow::Continue(()) + } +} diff --git a/lib/tmp/src/fmt/dbus/mod.rs b/lib/tmp/src/fmt/dbus/mod.rs index 720ccd3..49cab0b 100644 --- a/lib/tmp/src/fmt/dbus/mod.rs +++ b/lib/tmp/src/fmt/dbus/mod.rs @@ -1,7 +1,26 @@ //! # D-Bus Variants +//! +//! XXX +pub mod dvar; pub mod element; +pub mod ende; pub mod signature; pub use element::Element; pub use signature::{Cursor, Sig, sig}; + +#[derive(Clone, Copy, Debug, Hash)] +#[derive(Eq, Ord, PartialEq, PartialOrd)] +pub enum Error { + /// The underlying I/O operation failed. + Io(crate::io::map::Error), + /// The provided type does not match the signature. + Mismatch, + /// The signature has not been fully processed. + Pending, + /// The passed data overflows the supported length of the encoding. + DataOverflow, + /// The data is not valid UTF-8. + DataNonUtf8, +} diff --git a/meson_options.txt b/meson_options.txt index 23ca57d..5722fac 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,4 @@ option('doctest', type: 'boolean', value: false, description: 'Test code of documentation') option('libc', type: 'boolean', value: false, description: 'Use libc-rs as backend') +option('polonius', type: 'boolean', value: false, description: 'Assume running under the Polonius borrow checker') option('std', type: 'boolean', value: false, description: 'Provide integration with the Rust standard library')