logforth_core/
kv.rs

1// Copyright 2024 FastLabs Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Key-value pairs in a log record or a diagnostic context.
16
17// This file is derived from https://github.com/SpriteOvO/spdlog-rs/blob/788bda33/spdlog/src/kv.rs
18
19pub extern crate value_bag;
20
21use std::borrow::Cow;
22use std::fmt;
23use std::slice;
24use std::sync::Arc;
25
26use value_bag::OwnedValueBag;
27use value_bag::ValueBag;
28
29use crate::Error;
30use crate::str::Str;
31
32/// A visitor to walk through key-value pairs.
33pub trait Visitor {
34    /// Visit a key-value pair.
35    fn visit(&mut self, key: Key, value: Value) -> Result<(), Error>;
36}
37
38/// A value in a key-value pair.
39pub type Value<'a> = ValueBag<'a>;
40
41/// A key in a key-value pair.
42#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
43pub struct Key<'a>(Str<'a>);
44
45impl Key<'static> {
46    /// Create a new key from a static `&str`.
47    pub const fn new(k: &'static str) -> Key<'static> {
48        Key(Str::new(k))
49    }
50
51    /// Create a new key from a shared value.
52    ///
53    /// Cloning the key will involve cloning the `Arc`, which may be cheaper than cloning the
54    /// value itself.
55    pub fn new_shared(key: impl Into<Arc<str>>) -> Self {
56        Key(Str::new_shared(key))
57    }
58}
59
60impl<'a> Key<'a> {
61    /// Create a new key from a `&str`.
62    ///
63    /// The [`Key::new`] method should be preferred where possible.
64    pub const fn new_ref(k: &'a str) -> Key<'a> {
65        Key(Str::new_ref(k))
66    }
67
68    /// Convert to an owned key.
69    pub fn to_owned(&self) -> KeyOwned {
70        KeyOwned(self.0.to_shared())
71    }
72
73    /// Convert to a `Cow` str.
74    pub fn to_cow(&self) -> Cow<'static, str> {
75        self.0.to_cow()
76    }
77
78    /// Get the key string.
79    pub fn as_str(&self) -> &str {
80        self.0.get()
81    }
82}
83
84impl fmt::Display for Key<'_> {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        fmt::Display::fmt(&self.0, f)
87    }
88}
89
90/// An owned value in a key-value pair.
91pub type ValueOwned = OwnedValueBag;
92
93/// An owned key in a key-value pair.
94#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
95pub struct KeyOwned(Str<'static>);
96
97impl KeyOwned {
98    /// Create a `Key` ref.
99    pub fn by_ref(&self) -> Key<'_> {
100        Key(self.0.by_ref())
101    }
102}
103
104impl fmt::Display for KeyOwned {
105    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106        fmt::Display::fmt(&self.0, f)
107    }
108}
109
110/// A collection of key-value pairs.
111pub struct KeyValues<'a>(KeyValuesState<'a>);
112
113enum KeyValuesState<'a> {
114    Borrowed(&'a [(Key<'a>, Value<'a>)]),
115    Owned(&'a [(KeyOwned, ValueOwned)]),
116}
117
118impl<'a> KeyValues<'a> {
119    /// Get the number of key-value pairs.
120    pub fn len(&self) -> usize {
121        match self.0 {
122            KeyValuesState::Borrowed(p) => p.len(),
123            KeyValuesState::Owned(p) => p.len(),
124        }
125    }
126
127    /// Check if there are no key-value pairs.
128    pub fn is_empty(&self) -> bool {
129        match self.0 {
130            KeyValuesState::Borrowed(p) => p.is_empty(),
131            KeyValuesState::Owned(p) => p.is_empty(),
132        }
133    }
134
135    /// Get an iterator over the key-value pairs.
136    pub fn iter(&self) -> KeyValuesIter<'a> {
137        match &self.0 {
138            KeyValuesState::Borrowed(p) => KeyValuesIter(KeyValuesIterState::Borrowed(p.iter())),
139            KeyValuesState::Owned(p) => KeyValuesIter(KeyValuesIterState::Owned(p.iter())),
140        }
141    }
142
143    /// Get the value for a given key.
144    ///
145    /// If the key appears multiple times in the source then which key is returned is undetermined.
146    pub fn get(&self, key: &str) -> Option<Value<'a>> {
147        match &self.0 {
148            KeyValuesState::Borrowed(p) => p.iter().find_map(|(k, v)| {
149                if k.0.get() != key {
150                    None
151                } else {
152                    Some(v.clone())
153                }
154            }),
155            KeyValuesState::Owned(p) => p.iter().find_map(|(k, v)| {
156                if k.0.get() != key {
157                    None
158                } else {
159                    Some(v.by_ref())
160                }
161            }),
162        }
163    }
164
165    /// Visit the key-value pairs with the provided visitor.
166    pub fn visit(&self, visitor: &mut dyn Visitor) -> Result<(), Error> {
167        for (k, v) in self.iter() {
168            visitor.visit(k, v)?;
169        }
170        Ok(())
171    }
172}
173
174impl fmt::Debug for KeyValues<'_> {
175    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176        f.debug_list().entries(self.iter()).finish()
177    }
178}
179
180impl Clone for KeyValues<'_> {
181    fn clone(&self) -> Self {
182        match &self.0 {
183            KeyValuesState::Borrowed(p) => KeyValues(KeyValuesState::Borrowed(p)),
184            KeyValuesState::Owned(p) => KeyValues(KeyValuesState::Owned(p)),
185        }
186    }
187}
188
189impl Default for KeyValues<'_> {
190    fn default() -> Self {
191        KeyValues(KeyValuesState::Borrowed(&[]))
192    }
193}
194
195impl<'a> IntoIterator for KeyValues<'a> {
196    type Item = (Key<'a>, Value<'a>);
197    type IntoIter = KeyValuesIter<'a>;
198
199    fn into_iter(self) -> Self::IntoIter {
200        self.iter()
201    }
202}
203
204impl<'a> From<&'a [(Key<'a>, Value<'a>)]> for KeyValues<'a> {
205    fn from(kvs: &'a [(Key<'a>, Value<'a>)]) -> Self {
206        Self(KeyValuesState::Borrowed(kvs))
207    }
208}
209
210impl<'a> From<&'a [(KeyOwned, ValueOwned)]> for KeyValues<'a> {
211    fn from(kvs: &'a [(KeyOwned, ValueOwned)]) -> Self {
212        Self(KeyValuesState::Owned(kvs))
213    }
214}
215
216/// An iterator over key-value pairs.
217pub struct KeyValuesIter<'a>(KeyValuesIterState<'a>);
218
219enum KeyValuesIterState<'a> {
220    Borrowed(slice::Iter<'a, (Key<'a>, Value<'a>)>),
221    Owned(slice::Iter<'a, (KeyOwned, ValueOwned)>),
222}
223
224impl<'a> Iterator for KeyValuesIter<'a> {
225    type Item = (Key<'a>, Value<'a>);
226
227    fn next(&mut self) -> Option<Self::Item> {
228        match &mut self.0 {
229            KeyValuesIterState::Borrowed(iter) => iter.next().map(|(k, v)| (k.clone(), v.clone())),
230            KeyValuesIterState::Owned(iter) => iter.next().map(|(k, v)| (k.by_ref(), v.by_ref())),
231        }
232    }
233
234    fn size_hint(&self) -> (usize, Option<usize>) {
235        match &self.0 {
236            KeyValuesIterState::Borrowed(iter) => iter.size_hint(),
237            KeyValuesIterState::Owned(iter) => iter.size_hint(),
238        }
239    }
240}