From b9362a2edc25fdf3fe8dac878a170b19492cf1d1 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 2 Feb 2024 07:37:15 -0800 Subject: [PATCH] KeyVisitor::visit_other() Refs #314 --- CHANGELOG.md | 4 +++ crates/bonsaidb-core/src/key.rs | 64 ++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5e2aefac8..d1c4daf319 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `bonsaidb::client::Error` now implements `From>`. +- `KeyVisitor::visit_other` is a new function that indicates the key encoded is + a byte sequence of a known type. ### Fixed @@ -32,6 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Entry` - `EntryInsert` - `EntryUpdate` +- `KeyDescriber` no longer panics when a `Key` type calls no visitor methods in + its `KeyEncoding::describe` implementation. ## v0.5.0 diff --git a/crates/bonsaidb-core/src/key.rs b/crates/bonsaidb-core/src/key.rs index d1fcc772ce..e16d0c1afe 100644 --- a/crates/bonsaidb-core/src/key.rs +++ b/crates/bonsaidb-core/src/key.rs @@ -4,6 +4,7 @@ mod varint; mod deprecated; +use std::any::type_name; use std::borrow::{Borrow, Cow}; use std::collections::HashMap; use std::convert::Infallible; @@ -244,6 +245,10 @@ pub trait KeyVisitor { /// Report that a basic key type is encoded next in this key. fn visit_type(&mut self, kind: KeyKind); + /// Report that a custom type is encoded next as a single byte sequence in + /// this key. + fn visit_other(&mut self, kind: impl Into>); + /// Report that a composite type made up of `count` fields is encoded next in /// this key. /// @@ -411,12 +416,10 @@ impl KeyDescription { /// This function will panic if `KE` emits an imbalanced sequence of visit /// calls. #[must_use] - pub fn for_encoding, K: for<'k> Key<'k>>() -> Self { + pub fn for_encoding, K: for<'k> Key<'k> + 'static>() -> Self { let mut describer = KeyDescriber::default(); KE::describe(&mut describer); - describer - .result - .expect("invalid KeyEncoding::describe implementation -- imbalanced visit calls") + describer.finish_for::() } /// Returns the description of a given [`Key`] implementor. @@ -426,7 +429,7 @@ impl KeyDescription { /// This function will panic if `KE` emits an imbalanced sequence of visit /// calls. #[must_use] - pub fn for_key Key<'k>>() -> Self { + pub fn for_key Key<'k> + 'static>() -> Self { Self::for_encoding::() } } @@ -465,6 +468,18 @@ impl KeyDescriber { } } } + + fn finish_for(self) -> KeyDescription + where + T: 'static, + { + assert!( + self.stack.is_empty(), + "invalid KeyEncoding::describe implementation -- imbalanced visit calls" + ); + self.result + .unwrap_or_else(|| KeyDescription::Other(Cow::Borrowed(type_name::()))) + } } impl KeyVisitor for KeyDescriber { @@ -473,6 +488,10 @@ impl KeyVisitor for KeyDescriber { self.record(description); } + fn visit_other(&mut self, kind: impl Into>) { + self.record(KeyDescription::Other(kind.into())); + } + fn visit_composite(&mut self, kind: CompositeKind, count: usize) { self.stack.push(CompositeKeyDescription { kind, @@ -2759,6 +2778,34 @@ fn enum_derive_tests() -> anyhow::Result<()> { #[test] fn key_descriptions() { use time::limited::TimeEpoch; + + #[derive(Clone)] + struct NoDescriptionKey; + + impl<'k> Key<'k> for NoDescriptionKey { + const CAN_OWN_BYTES: bool = false; + + fn from_ord_bytes<'e>(_bytes: ByteSource<'k, 'e>) -> Result { + Ok(NoDescriptionKey) + } + } + + impl KeyEncoding for NoDescriptionKey { + type Error = Infallible; + + const LENGTH: Option = None; + + fn describe(_visitor: &mut Visitor) + where + Visitor: KeyVisitor, + { + } + + fn as_ord_bytes(&self) -> Result, Self::Error> { + Ok(Cow::Borrowed(b"")) + } + } + assert_eq!( KeyDescription::for_key::>(), KeyDescription::Basic(KeyKind::Bytes) @@ -2790,6 +2837,13 @@ fn key_descriptions() { attributes: HashMap::new(), }) ); + + assert_eq!( + KeyDescription::for_key::(), + KeyDescription::Other(Cow::Borrowed( + "bonsaidb_core::key::key_descriptions::NoDescriptionKey" + )) + ); } #[test]