1#[cfg(feature = "std")]
2use std::rc::Rc;
3
4use crate::{
5 val::ValConvert,
6 xdr::{ScErrorCode, ScErrorType},
7 Env, Error, Tag, Val,
8};
9use core::cmp::Ordering;
10
11pub trait Compare<T> {
23 type Error;
24 fn compare(&self, a: &T, b: &T) -> Result<Ordering, Self::Error>;
25}
26
27impl<T, C: Compare<T>> Compare<&T> for C {
28 type Error = C::Error;
29
30 fn compare(&self, a: &&T, b: &&T) -> Result<Ordering, Self::Error> {
31 <C as Compare<T>>::compare(self, *a, *b)
32 }
33}
34
35impl<T, C: Compare<T>> Compare<Option<T>> for C {
36 type Error = C::Error;
37
38 fn compare(&self, a: &Option<T>, b: &Option<T>) -> Result<Ordering, Self::Error> {
39 match (a, b) {
40 (Some(a), Some(b)) => <C as Compare<T>>::compare(self, a, b),
41 (None, None) => Ok(Ordering::Equal),
42 (None, Some(_)) => Ok(Ordering::Less),
43 (Some(_), None) => Ok(Ordering::Greater),
44 }
45 }
46}
47
48macro_rules! impl_compare_for_tuple {
49 ( $($idx:tt $T:ident),+) => {
50 impl<$($T,)+ E, C> Compare<($($T,)+)> for C
51 where
52 $(C: Compare<$T, Error = E>,)+
53 {
54 type Error = E;
55
56 fn compare(&self, a: &($($T,)+), b: &($($T,)+)) -> Result<Ordering, Self::Error> {
57 $(
58 match <C as Compare<$T>>::compare(self, &a.$idx, &b.$idx)? {
59 unequal @ (Ordering::Less | Ordering::Greater) => return Ok(unequal),
60 _ => ()
61 }
62 )*
63 Ok(Ordering::Equal)
64 }
65 }
66 };
67}
68
69impl_compare_for_tuple!(0 T, 1 U);
70impl_compare_for_tuple!(0 T, 1 U, 2 V);
71impl_compare_for_tuple!(0 T, 1 U, 2 V, 3 W);
72impl_compare_for_tuple!(0 T, 1 U, 2 V, 3 W, 4 X);
73
74#[cfg(feature = "std")]
75impl<T, C: Compare<T>> Compare<Vec<T>> for C {
76 type Error = C::Error;
77
78 fn compare(&self, a: &Vec<T>, b: &Vec<T>) -> Result<Ordering, Self::Error> {
79 let mut i = 0;
80 loop {
81 match (a.get(i), b.get(i)) {
82 (None, None) => return Ok(Ordering::Equal),
83 (None, Some(_)) => return Ok(Ordering::Less),
84 (Some(_), None) => return Ok(Ordering::Greater),
85 (Some(a), Some(b)) => match <C as Compare<T>>::compare(self, a, b)? {
86 Ordering::Equal => i += 1,
87 unequal => return Ok(unequal),
88 },
89 }
90 }
91 }
92}
93
94#[cfg(feature = "std")]
95impl<T, C: Compare<T>> Compare<Box<T>> for C {
96 type Error = C::Error;
97
98 fn compare(&self, a: &Box<T>, b: &Box<T>) -> Result<Ordering, Self::Error> {
99 <Self as Compare<T>>::compare(self, a, b)
100 }
101}
102
103#[cfg(feature = "std")]
104impl<T, C: Compare<T>> Compare<Rc<T>> for C {
105 type Error = C::Error;
106
107 fn compare(&self, a: &Rc<T>, b: &Rc<T>) -> Result<Ordering, Self::Error> {
108 <Self as Compare<T>>::compare(self, a, b)
109 }
110}
111
112macro_rules! delegate_compare_to_wrapper {
119 ($T:ident,$A:ident,$B:ident,$SELF:ident) => {{
120 let a = unsafe { crate::$T::unchecked_from_val(*$A) };
121 let b = unsafe { crate::$T::unchecked_from_val(*$B) };
122 $SELF.compare(&a, &b)
123 }};
124}
125
126#[allow(clippy::comparison_chain)]
127impl<E: Env> Compare<Val> for E {
128 type Error = E::Error;
129
130 fn compare(&self, a: &Val, b: &Val) -> Result<Ordering, Self::Error> {
131 if a.get_payload() == b.get_payload() {
132 return Ok(Ordering::Equal);
134 }
135 if a.is_object() || b.is_object() {
136 let v = self.obj_cmp(*a, *b)?;
138 return if v == 0 {
139 Ok(Ordering::Equal)
140 } else if v < 0 {
141 Ok(Ordering::Less)
142 } else {
143 Ok(Ordering::Greater)
144 };
145 }
146 let a_tag = a.get_tag();
147 let b_tag = b.get_tag();
148 if a_tag < b_tag {
149 Ok(Ordering::Less)
150 } else if a_tag > b_tag {
151 Ok(Ordering::Greater)
152 } else {
153 match a_tag {
155 Tag::False => Ok(Ordering::Equal),
156 Tag::True => Ok(Ordering::Equal),
157 Tag::Void => Ok(Ordering::Equal),
158
159 Tag::Error => delegate_compare_to_wrapper!(Error, a, b, self),
160
161 Tag::U32Val => delegate_compare_to_wrapper!(U32Val, a, b, self),
162 Tag::I32Val => delegate_compare_to_wrapper!(I32Val, a, b, self),
163
164 Tag::U64Small => delegate_compare_to_wrapper!(U64Small, a, b, self),
165 Tag::I64Small => delegate_compare_to_wrapper!(I64Small, a, b, self),
166
167 Tag::TimepointSmall => delegate_compare_to_wrapper!(TimepointSmall, a, b, self),
168 Tag::DurationSmall => delegate_compare_to_wrapper!(DurationSmall, a, b, self),
169
170 Tag::U128Small => delegate_compare_to_wrapper!(U128Small, a, b, self),
171 Tag::I128Small => delegate_compare_to_wrapper!(I128Small, a, b, self),
172
173 Tag::U256Small => delegate_compare_to_wrapper!(U256Small, a, b, self),
174 Tag::I256Small => delegate_compare_to_wrapper!(I256Small, a, b, self),
175
176 Tag::SymbolSmall => delegate_compare_to_wrapper!(SymbolSmall, a, b, self),
177
178 Tag::SmallCodeUpperBound => Ok(Ordering::Equal),
179 Tag::ObjectCodeLowerBound => Ok(Ordering::Equal),
180
181 Tag::U64Object
185 | Tag::I64Object
186 | Tag::TimepointObject
187 | Tag::DurationObject
188 | Tag::U128Object
189 | Tag::I128Object
190 | Tag::U256Object
191 | Tag::I256Object
192 | Tag::BytesObject
193 | Tag::StringObject
194 | Tag::SymbolObject
195 | Tag::VecObject
196 | Tag::MapObject
197 | Tag::AddressObject => Err(self.error_from_error_val(Error::from_type_and_code(
198 ScErrorType::Context,
199 ScErrorCode::InternalError,
200 ))),
201
202 Tag::ObjectCodeUpperBound => Ok(Ordering::Equal),
203 Tag::Bad => Ok(Ordering::Equal),
204 }
205 }
206 }
207}