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}