diff --git a/miniconf/Cargo.toml b/miniconf/Cargo.toml index 66c5754e..29b8b069 100644 --- a/miniconf/Cargo.toml +++ b/miniconf/Cargo.toml @@ -44,6 +44,7 @@ yafnv = "3.0.0" tokio = { version = "1.38.0", features = ["io-std", "rt", "macros"] } strum = { version = "0.26.3", features = ["derive"] } trybuild = { version = "1.0.99", features = ["diff"] } +serde_json = { version = "1.0.133" } [[test]] name = "arrays" diff --git a/miniconf/src/iter.rs b/miniconf/src/iter.rs index 223d53e6..6530c842 100644 --- a/miniconf/src/iter.rs +++ b/miniconf/src/iter.rs @@ -100,7 +100,8 @@ impl NodeIter { /// /// This requires moving `self` to ensure `FusedIterator`. pub fn root(mut self, root: K) -> Result { - self.root = self.state.transcode::(root)?.depth(); + let node = self.state.transcode::(root)?; + self.root = node.depth(); self.depth = D + 1; Ok(self) } diff --git a/miniconf/src/packed.rs b/miniconf/src/packed.rs index daf432c4..7e0b127c 100644 --- a/miniconf/src/packed.rs +++ b/miniconf/src/packed.rs @@ -154,10 +154,16 @@ impl Packed { *self = Self::EMPTY; } + /// Number of bits that can be stored. + #[inline] + pub const fn capacity(&self) -> u32 { + self.0.trailing_zeros() + } + /// Number of bits stored. #[inline] pub const fn len(&self) -> u32 { - Self::CAPACITY - self.0.trailing_zeros() + Self::CAPACITY - self.capacity() } /// Return the representation aligned to the LSB with the marker bit diff --git a/miniconf/src/tree.rs b/miniconf/src/tree.rs index 65464749..ef769947 100644 --- a/miniconf/src/tree.rs +++ b/miniconf/src/tree.rs @@ -431,7 +431,7 @@ pub trait TreeDeserialize<'de> { /// Deserialize a leaf node by its keys. /// /// ``` - /// # #[cfg(feature = "json-core")] { + /// # #[cfg(feature = "derive")] { /// use miniconf::{IntoKeys, Leaf, TreeDeserialize, TreeKey}; /// #[derive(Default, TreeKey, TreeDeserialize)] /// struct S { @@ -439,7 +439,7 @@ pub trait TreeDeserialize<'de> { /// bar: [Leaf; 2], /// }; /// let mut s = S::default(); - /// let mut de = serde_json_core::de::Deserializer::new(b"7", None); + /// let mut de = serde_json::de::Deserializer::from_slice(b"7"); /// s.deserialize_by_key(["bar", "0"].into_keys(), &mut de) /// .unwrap(); /// de.end().unwrap(); diff --git a/miniconf_derive/src/field.rs b/miniconf_derive/src/field.rs index df6b6835..c53a5600 100644 --- a/miniconf_derive/src/field.rs +++ b/miniconf_derive/src/field.rs @@ -159,8 +159,8 @@ impl TreeField { let getter = self.getter(i); quote_spanned! { self.span()=> #getter - .and_then(|value| - ::miniconf::TreeSerialize::serialize_by_key(value, keys, ser) + .and_then(|item| + ::miniconf::TreeSerialize::serialize_by_key(item, keys, ser) ) } } diff --git a/miniconf_derive/src/lib.rs b/miniconf_derive/src/lib.rs index f25f9f32..7882830c 100644 --- a/miniconf_derive/src/lib.rs +++ b/miniconf_derive/src/lib.rs @@ -61,7 +61,6 @@ pub fn derive_tree(input: TokenStream) -> TokenStream { t.tree_any(), ] .into_iter() - .flatten() .collect(), Err(e) => e.write_errors(), } diff --git a/miniconf_derive/src/tree.rs b/miniconf_derive/src/tree.rs index 096c6424..58cf4c22 100644 --- a/miniconf_derive/src/tree.rs +++ b/miniconf_derive/src/tree.rs @@ -22,7 +22,6 @@ pub struct TreeVariant { impl TreeVariant { fn parse(mut self) -> darling::Result { assert!(!self.fields.is_struct()); - // unnamed fields can only be skipped if they are terminal while self .fields .fields @@ -66,7 +65,6 @@ impl Tree { fn parse(mut self) -> darling::Result { match &mut self.data { Data::Struct(fields) => { - // unnamed fields can only be skipped if they are terminal while fields .fields .last() @@ -81,7 +79,7 @@ impl Tree { if let Some(f) = fields.fields.iter().find(|f| f.skip.is_present()) { return Err( // Note(design) If non-terminal fields are skipped, there is a gap in the indices. - // This could be lifted with a index map. + // This could be lifted with an index map. Error::custom("Can only `skip` terminal tuple struct fields") .with_span(&f.skip.span()), ); @@ -266,7 +264,6 @@ impl Tree { { let index = #index?; #traverse - #[allow(unreachable_code)] #increment(match index { #(#traverse_arms ,)* _ => unreachable!() @@ -294,8 +291,6 @@ impl Tree { S: ::miniconf::Serializer, { let index = #index?; - // Note(unreachable) empty structs have diverged by now - #[allow(unreachable_code)] #increment(match #mat { #(#arms ,)* _ => #default @@ -336,8 +331,6 @@ impl Tree { D: ::miniconf::Deserializer<'de>, { let index = #index?; - // Note(unreachable) empty structs have diverged by now - #[allow(unreachable_code)] #increment(match #mat { #(#arms ,)* _ => #default @@ -365,15 +358,11 @@ impl Tree { K: ::miniconf::Keys, { let index = #index?; - // Note(unreachable) empty structs have diverged by now - #[allow(unreachable_code)] - { - let ret: ::core::result::Result<_, _> = match #mat { - #(#ref_arms ,)* - _ => #default - }; - ret #increment - } + let ret: ::core::result::Result<_, _> = match #mat { + #(#ref_arms ,)* + _ => #default + }; + ret #increment } fn mut_any_by_key(&mut self, mut keys: K) -> ::core::result::Result<&mut dyn ::core::any::Any, ::miniconf::Traversal> @@ -381,15 +370,11 @@ impl Tree { K: ::miniconf::Keys, { let index = #index?; - // Note(unreachable) empty structs have diverged by now - #[allow(unreachable_code)] - { - let ret: ::core::result::Result<_, _> = match #mat { - #(#mut_arms ,)* - _ => #default - }; - ret #increment - } + let ret: ::core::result::Result<_, _> = match #mat { + #(#mut_arms ,)* + _ => #default + }; + ret #increment } } } diff --git a/py/miniconf-mqtt/miniconf/__main__.py b/py/miniconf-mqtt/miniconf/__main__.py index 4468cbbc..7af6ef3c 100644 --- a/py/miniconf-mqtt/miniconf/__main__.py +++ b/py/miniconf-mqtt/miniconf/__main__.py @@ -119,6 +119,7 @@ async def run(): assert path.startswith("/") or not path value = await interface.get(path) print(f"{path}={value}") + await interface.close() asyncio.run(run()) diff --git a/py/miniconf-mqtt/miniconf/miniconf.py b/py/miniconf-mqtt/miniconf/miniconf.py index e5640f21..6672ea58 100644 --- a/py/miniconf-mqtt/miniconf/miniconf.py +++ b/py/miniconf-mqtt/miniconf/miniconf.py @@ -50,6 +50,18 @@ def __init__(self, client: Client, prefix: str): self.listener = asyncio.create_task(self._listen()) self.subscribed = asyncio.Event() + async def close(self): + """Cancel the response listener and all in-flight requests""" + self.listener.cancel() + for fut in self._inflight.values(): + fut.cancel() + try: + await self.listener + except asyncio.CancelledError: + pass + if len(self._inflight) > 0: + await asyncio.wait(self._inflight.values()) + async def _listen(self): await self.client.subscribe(self.response_topic) LOGGER.info(f"Subscribed to {self.response_topic}")