Skip to main content

cbor_core/
value_key.rs

1use std::{borrow::Cow, collections::BTreeMap};
2
3use crate::{
4    Array, ByteString, DateTime, EpochTime, Float, Map, SimpleValue, TextString, 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`], [`Value::contains`], and the [`Index`]/[`IndexMut`]
13/// implementations on [`Value`]. You rarely name it directly: it converts
14/// from the same inputs that build a [`Value`], so the same arguments work
15/// for both.
16///
17/// Where building a [`Value`] from a reference would copy, `ValueKey`
18/// borrows instead, so a lookup allocates nothing:
19///
20/// - `&str`, `&String`, `&[u8]`, `&[u8; N]` borrow the string data.
21/// - `&Value` borrows the value.
22/// - `&[Value]`, `&Vec<Value>`, `&[Value; N]`, `&Array` borrow an
23///   array-valued key; `&Map` and `&BTreeMap<Value, Value>` borrow a
24///   map-valued key, bypassing the full-[`Value`] allocation a composite
25///   key would otherwise need.
26///
27/// Integers, floats, `bool`, `SimpleValue`, `()`, `char`, and owned inputs
28/// (an owned `Value`, `String`, `Vec<u8>`, `Array`, `Map`, and so on) are
29/// taken by value.
30///
31/// # Examples
32///
33/// ```
34/// use cbor_core::{Value, array, map};
35///
36/// let a = array![10, 20, 30];
37/// assert_eq!(a[1].to_u32(), Ok(20));
38///
39/// let m = map! { "x" => 10, 2 => 20 };
40/// assert_eq!(m["x"].to_u32(), Ok(10));
41/// assert_eq!(m[2].to_u32(), Ok(20));
42///
43/// let k: [Value; _] = [1,2,3].map(Value::from);
44/// let m = map! { k.clone() => "array as key" };
45/// assert_eq!(m[&k].as_str(), Ok("array as key") );
46///
47/// let mut v = array![1, 2, 3];
48/// v.remove(0);
49/// assert_eq!(v.len(), Some(2));
50/// ```
51///
52/// [`Index`]: std::ops::Index
53/// [`IndexMut`]: std::ops::IndexMut
54#[derive(Debug)]
55pub struct ValueKey<'a>(Inner<'a>);
56
57#[derive(Debug)]
58enum Inner<'a> {
59    Array(&'a [Value<'a>]),
60    Map(&'a BTreeMap<Value<'a>, Value<'a>>),
61    Other(Cow<'a, Value<'a>>),
62}
63
64impl ValueKey<'_> {
65    pub(crate) fn to_usize(&self) -> Option<usize> {
66        if let Inner::Other(value) = &self.0 {
67            value.to_usize().ok()
68        } else {
69            None
70        }
71    }
72}
73
74impl<'a> From<Value<'a>> for ValueKey<'a> {
75    fn from(value: Value<'a>) -> Self {
76        Self(Inner::Other(Cow::Owned(value)))
77    }
78}
79
80impl<'a> From<&'a Value<'a>> for ValueKey<'a> {
81    fn from(value: &'a Value<'a>) -> Self {
82        Self(Inner::Other(Cow::Borrowed(value)))
83    }
84}
85
86impl<'a> From<&'a [Value<'a>]> for ValueKey<'a> {
87    fn from(value: &'a [Value<'a>]) -> Self {
88        Self(Inner::Array(value))
89    }
90}
91
92impl<'a> From<&'a Array<'a>> for ValueKey<'a> {
93    fn from(value: &'a Array<'a>) -> Self {
94        Self(Inner::Array(&value.0))
95    }
96}
97
98impl<'a> From<&'a Map<'a>> for ValueKey<'a> {
99    fn from(value: &'a Map<'a>) -> Self {
100        Self(Inner::Map(&value.0))
101    }
102}
103
104impl<'a> From<&'a BTreeMap<Value<'a>, Value<'a>>> for ValueKey<'a> {
105    fn from(value: &'a BTreeMap<Value<'a>, Value<'a>>) -> Self {
106        Self(Inner::Map(value))
107    }
108}
109
110impl<'a, T> From<&'a Vec<T>> for ValueKey<'a>
111where
112    ValueKey<'a>: From<&'a [T]>,
113{
114    fn from(value: &'a Vec<T>) -> Self {
115        value.as_slice().into()
116    }
117}
118
119impl<'a, T, const N: usize> From<&'a [T; N]> for ValueKey<'a>
120where
121    ValueKey<'a>: From<&'a [T]>,
122{
123    fn from(value: &'a [T; N]) -> Self {
124        value.as_slice().into()
125    }
126}
127
128impl<'a, const N: usize> From<[u8; N]> for ValueKey<'a> {
129    fn from(value: [u8; N]) -> Self {
130        Self(Inner::Other(Cow::Owned(Value::from(value))))
131    }
132}
133
134impl<'a, const N: usize> From<[Value<'a>; N]> for ValueKey<'a> {
135    fn from(value: [Value<'a>; N]) -> Self {
136        Self(Inner::Other(Cow::Owned(Value::from(value))))
137    }
138}
139
140/// Conversions that build a [`Value`] and store it as an owned key.
141///
142/// The owned [`Cow`] wrapper does not imply an allocation: for a reference
143/// (`&str`, `&[u8]`, ...) the [`Value`] it holds borrows the data, and for
144/// an owned input the data is moved through. Only conversions whose
145/// [`Value`] counterpart allocates do.
146macro_rules! impl_from {
147    ($($type:ty),* $(,)?) => { $(
148        impl<'a> From<$type> for ValueKey<'a> {
149            fn from(value: $type) -> Self {
150                Self(Inner::Other(Cow::Owned(Value::from(value))))
151            }
152        }
153    )* }
154}
155
156impl_from!(bool, SimpleValue, (), char);
157impl_from!(u8, u16, u32, u64, u128, usize);
158impl_from!(i8, i16, i32, i64, i128, isize);
159impl_from!(f32, f64, Float);
160impl_from!(DateTime, &'a DateTime, EpochTime);
161impl_from!(TextString<'a>, &'a TextString<'a>, ByteString<'a>, &'a ByteString<'a>);
162impl_from!(&'a str, &'a String, String, Box<str>, Cow<'a, str>);
163impl_from!(&'a [u8], Vec<u8>, Box<[u8]>, Cow<'a, [u8]>);
164impl_from!(Array<'a>, Map<'a>);
165impl_from!(Vec<Value<'a>>, Box<[Value<'a>]>, BTreeMap<Value<'a>, Value<'a>>);
166
167impl ValueView for ValueKey<'_> {
168    fn head(&self) -> Head {
169        match &self.0 {
170            Inner::Array(arr) => Head::from_usize(Major::Array, arr.len()),
171            Inner::Map(map) => Head::from_usize(Major::Map, map.len()),
172            Inner::Other(value) => value.head(),
173        }
174    }
175
176    fn payload(&self) -> Payload<'_> {
177        match &self.0 {
178            Inner::Array(arr) => Payload::Array(arr),
179            Inner::Map(map) => Payload::Map(map),
180            Inner::Other(value) => value.payload(),
181        }
182    }
183}