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::fmt;
22use std::slice;
23
24use value_bag::OwnedValueBag;
25use value_bag::ValueBag;
26
27use crate::Error;
28use crate::str::Str;
29
30/// A visitor to walk through key-value pairs.
31pub trait Visitor {
32    /// Visits a key-value pair.
33    fn visit(&mut self, key: Key, value: Value) -> Result<(), Error>;
34}
35
36/// A value in a key-value pair.
37pub type Value<'a> = ValueBag<'a>;
38
39/// A key in a key-value pair.
40#[derive(Debug, Clone)]
41pub struct Key<'a>(Str<'a>);
42
43impl<'a> Key<'a> {
44    /// Convert to an owned `String`.
45    pub fn into_string(self) -> String {
46        self.0.into_string()
47    }
48
49    /// Convert to an owned key.
50    pub fn to_owned(&self) -> KeyOwned {
51        KeyOwned(self.0.to_owned())
52    }
53
54    /// Get the key string.
55    pub fn as_str(&self) -> &str {
56        self.0.get()
57    }
58
59    /// Coerce to a key with a shorter lifetime.
60    pub fn coerce(&self) -> Key<'_> {
61        Key(self.0.by_ref())
62    }
63}
64
65impl fmt::Display for Key<'_> {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        fmt::Display::fmt(&self.0, f)
68    }
69}
70
71impl<'a> From<Str<'a>> for Key<'a> {
72    fn from(s: Str<'a>) -> Self {
73        Key(s)
74    }
75}
76
77impl<'a> From<&'a str> for Key<'a> {
78    fn from(s: &'a str) -> Self {
79        Key(Str::from(s))
80    }
81}
82
83/// An owned value in a key-value pair.
84pub type ValueOwned = OwnedValueBag;
85
86/// An owned key in a key-value pair.
87#[derive(Debug, Clone)]
88pub struct KeyOwned(Str<'static>);
89
90impl KeyOwned {
91    /// Create a `Key` ref.
92    pub fn by_ref(&self) -> Key<'_> {
93        Key(self.0.by_ref())
94    }
95}
96
97impl fmt::Display for KeyOwned {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        fmt::Display::fmt(&self.0, f)
100    }
101}
102
103/// A collection of key-value pairs.
104pub struct KeyValues<'a>(KeyValuesState<'a>);
105
106enum KeyValuesState<'a> {
107    Borrowed(&'a [(Key<'a>, Value<'a>)]),
108    Owned(&'a [(KeyOwned, ValueOwned)]),
109}
110
111impl<'a> KeyValues<'a> {
112    /// Get the number of key-value pairs.
113    pub fn len(&self) -> usize {
114        match self.0 {
115            KeyValuesState::Borrowed(p) => p.len(),
116            KeyValuesState::Owned(p) => p.len(),
117        }
118    }
119
120    /// Check if there are no key-value pairs.
121    pub fn is_empty(&self) -> bool {
122        match self.0 {
123            KeyValuesState::Borrowed(p) => p.is_empty(),
124            KeyValuesState::Owned(p) => p.is_empty(),
125        }
126    }
127
128    /// Get an iterator over the key-value pairs.
129    pub fn iter(&self) -> KeyValuesIter<'a> {
130        match &self.0 {
131            KeyValuesState::Borrowed(p) => KeyValuesIter(KeyValuesIterState::Borrowed(p.iter())),
132            KeyValuesState::Owned(p) => KeyValuesIter(KeyValuesIterState::Owned(p.iter())),
133        }
134    }
135
136    /// Visit the key-value pairs with the provided visitor.
137    pub fn visit(&self, visitor: &mut dyn Visitor) -> Result<(), Error> {
138        for (k, v) in self.iter() {
139            visitor.visit(k, v)?;
140        }
141        Ok(())
142    }
143}
144
145impl fmt::Debug for KeyValues<'_> {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        f.debug_list().entries(self.iter()).finish()
148    }
149}
150
151impl Clone for KeyValues<'_> {
152    fn clone(&self) -> Self {
153        match &self.0 {
154            KeyValuesState::Borrowed(p) => KeyValues(KeyValuesState::Borrowed(p)),
155            KeyValuesState::Owned(p) => KeyValues(KeyValuesState::Owned(p)),
156        }
157    }
158}
159
160impl Default for KeyValues<'_> {
161    fn default() -> Self {
162        KeyValues(KeyValuesState::Borrowed(&[]))
163    }
164}
165
166impl<'a> IntoIterator for KeyValues<'a> {
167    type Item = (Key<'a>, Value<'a>);
168    type IntoIter = KeyValuesIter<'a>;
169
170    fn into_iter(self) -> Self::IntoIter {
171        self.iter()
172    }
173}
174
175impl<'a> From<&'a [(Key<'a>, Value<'a>)]> for KeyValues<'a> {
176    fn from(kvs: &'a [(Key<'a>, Value<'a>)]) -> Self {
177        Self(KeyValuesState::Borrowed(kvs))
178    }
179}
180
181impl<'a> From<&'a [(KeyOwned, ValueOwned)]> for KeyValues<'a> {
182    fn from(kvs: &'a [(KeyOwned, ValueOwned)]) -> Self {
183        Self(KeyValuesState::Owned(kvs))
184    }
185}
186
187/// An iterator over key-value pairs.
188pub struct KeyValuesIter<'a>(KeyValuesIterState<'a>);
189
190enum KeyValuesIterState<'a> {
191    Borrowed(slice::Iter<'a, (Key<'a>, Value<'a>)>),
192    Owned(slice::Iter<'a, (KeyOwned, ValueOwned)>),
193}
194
195impl<'a> Iterator for KeyValuesIter<'a> {
196    type Item = (Key<'a>, Value<'a>);
197
198    fn next(&mut self) -> Option<Self::Item> {
199        match &mut self.0 {
200            KeyValuesIterState::Borrowed(iter) => iter.next().map(|(k, v)| (k.clone(), v.clone())),
201            KeyValuesIterState::Owned(iter) => iter.next().map(|(k, v)| (k.by_ref(), v.by_ref())),
202        }
203    }
204
205    fn size_hint(&self) -> (usize, Option<usize>) {
206        match &self.0 {
207            KeyValuesIterState::Borrowed(iter) => iter.size_hint(),
208            KeyValuesIterState::Owned(iter) => iter.size_hint(),
209        }
210    }
211}