diff --git a/CHANGELOG.md b/CHANGELOG.md index 50c66caf..cb3254b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed * python module: don't emite whitespace in JSON to match serde-json-core (#92) +* `heapless::String` now implements `Miniconf` directly. ### Fixed * Python device discovery now only discovers unique device identifiers. See [#97](https://github.com/quartiq/miniconf/issues/97) + ## [0.5.0] - 2022-05-12 ### Changed diff --git a/src/lib.rs b/src/lib.rs index f9c1cd83..88f40dc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -330,67 +330,75 @@ pub trait Miniconf { macro_rules! impl_single { ($x:ty) => { impl Miniconf for $x { - fn string_set( - &mut self, - mut topic_parts: core::iter::Peekable>, - value: &[u8], - ) -> Result<(), Error> { - if topic_parts.peek().is_some() { - return Err(Error::PathTooLong); - } - *self = serde_json_core::from_slice(value)?.0; - Ok(()) + impl_single!(); + } + }; + + () => { + fn string_set( + &mut self, + mut topic_parts: core::iter::Peekable>, + value: &[u8], + ) -> Result<(), Error> { + if topic_parts.peek().is_some() { + return Err(Error::PathTooLong); } + *self = serde_json_core::from_slice(value)?.0; + Ok(()) + } - fn string_get( - &self, - mut topic_parts: core::iter::Peekable>, - value: &mut [u8], - ) -> Result { - if topic_parts.peek().is_some() { - return Err(Error::PathTooLong); - } + fn string_get( + &self, + mut topic_parts: core::iter::Peekable>, + value: &mut [u8], + ) -> Result { + if topic_parts.peek().is_some() { + return Err(Error::PathTooLong); + } - serde_json_core::to_slice(self, value).map_err(|_| Error::SerializationFailed) + serde_json_core::to_slice(self, value).map_err(|_| Error::SerializationFailed) + } + + fn get_metadata(&self) -> MiniconfMetadata { + MiniconfMetadata { + // No topic length is needed, as there are no sub-members. + max_topic_size: 0, + // One index is required for the current element. + max_depth: 1, } + } - fn get_metadata(&self) -> MiniconfMetadata { - MiniconfMetadata { - // No topic length is needed, as there are no sub-members. - max_topic_size: 0, - // One index is required for the current element. - max_depth: 1, - } + // This implementation is the base case for primitives where it will + // yield once for self, then return None on subsequent calls. + fn recurse_paths( + &self, + index: &mut [usize], + _topic: &mut heapless::String, + ) -> Option<()> { + if index.len() == 0 { + // Note: During expected execution paths using `iter()`, the size of the + // index stack is checked in advance to make sure this condition doesn't occur. + // However, it's possible to happen if the user manually calls `recurse_paths`. + unreachable!("Index stack too small"); } - // This implementation is the base case for primitives where it will - // yield once for self, then return None on subsequent calls. - fn recurse_paths( - &self, - index: &mut [usize], - _topic: &mut heapless::String, - ) -> Option<()> { - if index.len() == 0 { - // Note: During expected execution paths using `iter()`, the size of the - // index stack is checked in advance to make sure this condition doesn't occur. - // However, it's possible to happen if the user manually calls `recurse_paths`. - unreachable!("Index stack too small"); - } - - let i = index[0]; - index[0] += 1; - index[1..].iter_mut().for_each(|x| *x = 0); - - if i == 0 { - Some(()) - } else { - None - } + let i = index[0]; + index[0] += 1; + index[1..].iter_mut().for_each(|x| *x = 0); + + if i == 0 { + Some(()) + } else { + None } } }; } +impl Miniconf for heapless::String { + impl_single!(); +} + // Implement trait for the primitive types impl_single!(u8); impl_single!(u16); diff --git a/tests/structs.rs b/tests/structs.rs index 35897a32..1798b20f 100644 --- a/tests/structs.rs +++ b/tests/structs.rs @@ -78,3 +78,22 @@ fn recursive_struct() { assert_eq!(metadata.max_depth, 3); assert_eq!(metadata.max_topic_size, "c/a".len()); } + +#[test] +fn struct_with_string() { + #[derive(Miniconf, Default)] + struct Settings { + string: heapless::String<10>, + } + + let mut s = Settings::default(); + + let field = "string".split('/').peekable(); + let mut buf = [0u8; 256]; + let len = s.string_get(field, &mut buf).unwrap(); + assert_eq!(&buf[..len], b"\"\""); + + let field = "string".split('/').peekable(); + s.string_set(field, br#""test""#).unwrap(); + assert_eq!(s.string, "test"); +}