foundationdb_tuple/
element.rs

1use super::pack::{f32_to_u32_be_bytes, f64_to_u64_be_bytes};
2use super::{Bytes, Versionstamp};
3use std::{borrow::Cow, cmp};
4
5#[cfg(feature = "num-bigint")]
6use num_bigint::Sign;
7#[cfg(feature = "num-bigint")]
8use std::convert::TryFrom;
9
10#[derive(Clone, Debug)]
11pub enum Element<'a> {
12    Nil,
13    Bytes(Bytes<'a>),
14    String(Cow<'a, str>),
15    Tuple(Vec<Element<'a>>),
16    Int(i64),
17    #[cfg(feature = "num-bigint")]
18    BigInt(num_bigint::BigInt),
19    Float(f32),
20    Double(f64),
21    Bool(bool),
22    #[cfg(feature = "uuid")]
23    Uuid(uuid::Uuid),
24    Versionstamp(Versionstamp),
25}
26
27struct CmpElement<'a, 'b>(&'a Element<'b>);
28
29impl PartialEq for CmpElement<'_, '_> {
30    fn eq(&self, other: &Self) -> bool {
31        self.cmp(other) == cmp::Ordering::Equal
32    }
33}
34impl Eq for CmpElement<'_, '_> {}
35
36impl PartialOrd for CmpElement<'_, '_> {
37    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
38        Some(self.cmp(other))
39    }
40}
41
42impl Ord for CmpElement<'_, '_> {
43    fn cmp(&self, other: &Self) -> cmp::Ordering {
44        self.0
45            .code()
46            .cmp(&other.0.code())
47            .then_with(|| match (&self.0, &other.0) {
48                (Element::Bytes(a), Element::Bytes(b)) => a.cmp(b),
49                (Element::String(a), Element::String(b)) => a.cmp(b),
50                (Element::Tuple(a), Element::Tuple(b)) => {
51                    let a_values = a.iter().map(CmpElement);
52                    let b_values = b.iter().map(CmpElement);
53                    a_values.cmp(b_values)
54                }
55                (Element::Int(a), Element::Int(b)) => a.cmp(b),
56                #[cfg(feature = "num-bigint")]
57                (Element::BigInt(a), Element::BigInt(b)) => a.cmp(b),
58                #[cfg(feature = "num-bigint")]
59                (Element::BigInt(a), Element::Int(b)) => match i64::try_from(a) {
60                    Ok(a) => a.cmp(b),
61                    Err(_) => a.sign().cmp(&Sign::NoSign),
62                },
63                #[cfg(feature = "num-bigint")]
64                (Element::Int(a), Element::BigInt(b)) => match i64::try_from(b) {
65                    Ok(b) => a.cmp(&b),
66                    Err(_) => Sign::NoSign.cmp(&b.sign()),
67                },
68                (Element::Float(a), Element::Float(b)) => {
69                    f32_to_u32_be_bytes(*a).cmp(&f32_to_u32_be_bytes(*b))
70                }
71                (Element::Double(a), Element::Double(b)) => {
72                    f64_to_u64_be_bytes(*a).cmp(&f64_to_u64_be_bytes(*b))
73                }
74                #[cfg(feature = "uuid")]
75                (Element::Uuid(a), Element::Uuid(b)) => a.cmp(b),
76                (Element::Versionstamp(a), Element::Versionstamp(b)) => a.cmp(b),
77                _ => cmp::Ordering::Equal,
78            })
79    }
80}
81
82impl PartialEq for Element<'_> {
83    fn eq(&self, other: &Self) -> bool {
84        self.cmp(other) == cmp::Ordering::Equal
85    }
86}
87impl Eq for Element<'_> {}
88
89impl PartialOrd for Element<'_> {
90    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
91        Some(self.cmp(other))
92    }
93}
94impl Ord for Element<'_> {
95    fn cmp(&self, other: &Self) -> cmp::Ordering {
96        self.cmp_at_root(other)
97    }
98}
99
100impl<'a> Element<'a> {
101    fn code(&self) -> u8 {
102        match self {
103            Element::Nil => super::NIL,
104            Element::Bytes(_) => super::BYTES,
105            Element::String(_) => super::STRING,
106            Element::Tuple(_) => super::NESTED,
107            Element::Int(_) => super::INTZERO,
108            #[cfg(feature = "num-bigint")]
109            Element::BigInt(_) => super::INTZERO,
110            Element::Float(_) => super::FLOAT,
111            Element::Double(_) => super::DOUBLE,
112            Element::Bool(v) => {
113                if *v {
114                    super::TRUE
115                } else {
116                    super::FALSE
117                }
118            }
119            #[cfg(feature = "uuid")]
120            Element::Uuid(_) => super::UUID,
121            Element::Versionstamp(_) => super::VERSIONSTAMP,
122        }
123    }
124
125    #[inline]
126    fn cmp_values(&self) -> &[Self] {
127        match self {
128            Element::Tuple(v) => v.as_slice(),
129            v => std::slice::from_ref(v),
130        }
131    }
132
133    fn cmp_at_root(&self, b: &Element<'_>) -> cmp::Ordering {
134        let a_values = self.cmp_values().iter().map(CmpElement);
135        let b_values = b.cmp_values().iter().map(CmpElement);
136        a_values.cmp(b_values)
137    }
138
139    pub fn into_owned(self) -> Element<'static> {
140        match self {
141            Element::Nil => Element::Nil,
142            Element::Bytes(v) => Element::Bytes(v.into_owned().into()),
143            Element::String(v) => Element::String(Cow::Owned(v.into_owned())),
144            Element::Tuple(v) => Element::Tuple(v.into_iter().map(|e| e.into_owned()).collect()),
145            Element::Int(v) => Element::Int(v),
146            #[cfg(feature = "num-bigint")]
147            Element::BigInt(v) => Element::BigInt(v),
148            Element::Float(v) => Element::Float(v),
149            Element::Double(v) => Element::Double(v),
150            Element::Bool(v) => Element::Bool(v),
151            #[cfg(feature = "uuid")]
152            Element::Uuid(v) => Element::Uuid(v),
153            Element::Versionstamp(v) => Element::Versionstamp(v),
154        }
155    }
156
157    pub fn as_bytes(&self) -> Option<&Bytes> {
158        match self {
159            Element::Bytes(v) => Some(v),
160            _ => None,
161        }
162    }
163
164    pub fn as_str(&self) -> Option<&str> {
165        match self {
166            Element::String(v) => Some(v),
167            _ => None,
168        }
169    }
170
171    pub fn as_tuple(&self) -> Option<&[Element<'a>]> {
172        match self {
173            Element::Tuple(v) => Some(v.as_slice()),
174            _ => None,
175        }
176    }
177
178    pub fn as_i64(&self) -> Option<i64> {
179        match self {
180            Element::Int(v) => Some(*v),
181            #[cfg(feature = "num-bigint")]
182            Element::BigInt(v) => i64::try_from(v).ok(),
183            _ => None,
184        }
185    }
186
187    #[cfg(feature = "num-bigint")]
188    pub fn as_bigint(&self) -> Option<&num_bigint::BigInt> {
189        match self {
190            Element::BigInt(v) => Some(v),
191            _ => None,
192        }
193    }
194
195    pub fn as_f32(&self) -> Option<f32> {
196        match self {
197            Element::Float(v) => Some(*v),
198            _ => None,
199        }
200    }
201
202    pub fn as_f64(&self) -> Option<f64> {
203        match self {
204            Element::Double(v) => Some(*v),
205            _ => None,
206        }
207    }
208
209    pub fn as_bool(&self) -> Option<bool> {
210        match *self {
211            Element::Bool(v) => Some(v),
212            _ => None,
213        }
214    }
215
216    #[cfg(feature = "uuid")]
217    pub fn as_uuid(&self) -> Option<&uuid::Uuid> {
218        match self {
219            Element::Uuid(v) => Some(v),
220            _ => None,
221        }
222    }
223
224    pub fn as_versionstamp(&self) -> Option<&Versionstamp> {
225        match self {
226            Element::Versionstamp(v) => Some(v),
227            _ => None,
228        }
229    }
230}