Skip to main content

cbor_core/
value_key.rs

1use std::{borrow::Cow, collections::BTreeMap};
2
3use crate::{
4    Array, Float, Map, SimpleValue, Value,
5    codec::{Head, Major},
6    view::{Payload, ValueView},
7};
8
9/// A key for looking up elements in [`Value`] arrays and maps.
10///
11/// `ValueKey` is the parameter type of [`Value::get`], [`Value::get_mut`],
12/// [`Value::remove`], and the [`Index`]/[`IndexMut`] implementations on
13/// [`Value`]. You rarely name it directly: every type that implements
14/// `Into<ValueKey>` can be passed in, including:
15///
16/// - integers, floats, `bool`, `SimpleValue`, `()`
17/// - `&str`, `&String`
18/// - `&[u8]`
19/// - `&Value`
20/// - `&[Value]`, `&Vec<Value>`, `&[Value; N]`, `&Array` (array-valued keys)
21/// - `&Map`, `&BTreeMap<Value, Value>` (map-valued keys)
22///
23/// Lookups are zero-copy for the borrowed forms: passing `&str`, `&[u8]`,
24/// `&[Value]`, or `&BTreeMap<Value, Value>` does not allocate a full
25/// [`Value`] to compare against map keys.
26///
27/// # Examples
28///
29/// ```
30/// use cbor_core::{Value, array, map};
31///
32/// let a = array![10, 20, 30];
33/// assert_eq!(a[1].to_u32(), Ok(20));
34///
35/// let m = map! { "x" => 10, 2 => 20 };
36/// assert_eq!(m["x"].to_u32(), Ok(10));
37/// assert_eq!(m[2].to_u32(), Ok(20));
38///
39/// let k: [Value; _] = [1,2,3].map(Value::from);
40/// let m = map! { k.clone() => "array as key" };
41/// assert_eq!(m[&k].as_str(), Ok("array as key") );
42///
43/// let mut v = array![1, 2, 3];
44/// v.remove(0);
45/// assert_eq!(v.len(), Some(2));
46/// ```
47///
48/// [`Index`]: std::ops::Index
49/// [`IndexMut`]: std::ops::IndexMut
50#[derive(Debug)]
51pub struct ValueKey<'a>(Inner<'a>);
52
53#[derive(Debug)]
54enum Inner<'a> {
55    Bytes(&'a [u8]),
56    Text(&'a str),
57    Array(&'a [Value]),
58    Map(&'a BTreeMap<Value, Value>),
59    Other(Cow<'a, Value>),
60}
61
62impl<'a> ValueKey<'a> {
63    pub(crate) fn to_usize(&self) -> Option<usize> {
64        if let Inner::Other(value) = &self.0 {
65            value.to_usize().ok()
66        } else {
67            None
68        }
69    }
70}
71
72impl<'a> From<Value> for ValueKey<'a> {
73    fn from(value: Value) -> Self {
74        Self(Inner::Other(Cow::Owned(value)))
75    }
76}
77
78impl<'a> From<&'a Value> for ValueKey<'a> {
79    fn from(value: &'a Value) -> Self {
80        Self(Inner::Other(Cow::Borrowed(value)))
81    }
82}
83
84impl<'a> From<&'a [Value]> for ValueKey<'a> {
85    fn from(value: &'a [Value]) -> Self {
86        Self(Inner::Array(value))
87    }
88}
89
90impl<'a> From<&'a Array> for ValueKey<'a> {
91    fn from(value: &'a Array) -> Self {
92        Self(Inner::Array(&value.0))
93    }
94}
95
96impl<'a> From<&'a Map> for ValueKey<'a> {
97    fn from(value: &'a Map) -> Self {
98        Self(Inner::Map(&value.0))
99    }
100}
101
102impl<'a> From<&'a BTreeMap<Value, Value>> for ValueKey<'a> {
103    fn from(value: &'a BTreeMap<Value, Value>) -> Self {
104        Self(Inner::Map(value))
105    }
106}
107
108impl<'a> From<&'a str> for ValueKey<'a> {
109    fn from(value: &'a str) -> Self {
110        Self(Inner::Text(value))
111    }
112}
113
114impl<'a> From<&'a String> for ValueKey<'a> {
115    fn from(value: &'a String) -> Self {
116        Self(Inner::Text(value))
117    }
118}
119
120impl<'a> From<&'a [u8]> for ValueKey<'a> {
121    fn from(value: &'a [u8]) -> Self {
122        Self(Inner::Bytes(value))
123    }
124}
125
126impl<'a, T> From<&'a Vec<T>> for ValueKey<'a>
127where
128    ValueKey<'a>: From<&'a [T]>,
129{
130    fn from(value: &'a Vec<T>) -> Self {
131        value.as_slice().into()
132    }
133}
134
135impl<'a, T, const N: usize> From<&'a [T; N]> for ValueKey<'a>
136where
137    ValueKey<'a>: From<&'a [T]>,
138{
139    fn from(value: &'a [T; N]) -> Self {
140        value.as_slice().into()
141    }
142}
143
144macro_rules! impl_from_copy {
145    ($($type:ty),* $(,)?) => { $(
146        impl<'a> From<$type> for ValueKey<'a> {
147            fn from(value: $type) -> ValueKey<'a> {
148                Self(Inner::Other(Cow::Owned(Value::from(value))))
149            }
150        }
151    )* }
152}
153
154impl_from_copy!(bool, SimpleValue, ());
155
156impl_from_copy!(u8, u16, u32, u64, u128, usize);
157impl_from_copy!(i8, i16, i32, i64, i128, isize);
158
159impl_from_copy!(f32, f64, Float);
160
161impl ValueView for ValueKey<'_> {
162    fn head(&self) -> Head {
163        match &self.0 {
164            Inner::Bytes(bytes) => Head::from_usize(Major::ByteString, bytes.len()),
165            Inner::Text(text) => Head::from_usize(Major::TextString, text.len()),
166            Inner::Array(arr) => Head::from_usize(Major::Array, arr.len()),
167            Inner::Map(map) => Head::from_usize(Major::Map, map.len()),
168            Inner::Other(value) => value.head(),
169        }
170    }
171
172    fn payload(&self) -> Payload<'_> {
173        match &self.0 {
174            Inner::Bytes(bytes) => Payload::Bytes(bytes),
175            Inner::Text(text) => Payload::Text(text),
176            Inner::Array(arr) => Payload::Array(arr),
177            Inner::Map(map) => Payload::Map(map),
178            Inner::Other(value) => value.payload(),
179        }
180    }
181}