1use std::{
2 borrow::Borrow,
3 fmt,
4 ops::{Add, Div, Mul, Sub},
5 str::FromStr,
6};
7
8use num_bigint::{BigInt, TryFromBigIntError};
9use num_traits::{Signed, Zero};
10
11use crate::{
12 lexical::{self, LexicalFormOf},
13 Datatype, IntDatatype, IntegerDatatype, LongDatatype, NonNegativeIntegerDatatype,
14 NonPositiveIntegerDatatype, ParseXsd, ShortDatatype, UnsignedIntDatatype, UnsignedLongDatatype,
15 UnsignedShortDatatype, XsdValue,
16};
17
18use super::{Sign, I16_MIN, I32_MIN, I64_MIN, I8_MIN, U16_MAX, U32_MAX, U64_MAX, U8_MAX};
19
20mod non_negative_integer;
21mod non_positive_integer;
22
23pub use non_negative_integer::*;
24pub use non_positive_integer::*;
25
26#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
28#[repr(transparent)]
29pub struct Integer(BigInt);
30
31impl Integer {
32 #[inline(always)]
34 pub fn from_bigint_ref(n: &BigInt) -> &Self {
35 unsafe {
36 std::mem::transmute(n)
39 }
40 }
41
42 #[inline(always)]
44 pub fn from_bigint(n: BigInt) -> Self {
45 Self(n)
46 }
47
48 pub fn from_bytes_be(sign: Sign, bytes: &[u8]) -> Self {
49 Self(BigInt::from_bytes_be(sign, bytes))
50 }
51
52 pub fn from_bytes_le(sign: Sign, bytes: &[u8]) -> Self {
53 Self(BigInt::from_bytes_le(sign, bytes))
54 }
55
56 pub fn from_signed_bytes_be(bytes: &[u8]) -> Self {
57 Self(BigInt::from_signed_bytes_be(bytes))
58 }
59
60 pub fn from_signed_bytes_le(bytes: &[u8]) -> Self {
61 Self(BigInt::from_signed_bytes_le(bytes))
62 }
63
64 #[inline(always)]
65 pub fn zero() -> Self {
66 Self(BigInt::zero())
67 }
68
69 #[inline(always)]
70 pub fn is_zero(&self) -> bool {
71 self.0.is_zero()
72 }
73
74 #[inline(always)]
75 pub fn is_positive(&self) -> bool {
76 self.0.is_positive()
77 }
78
79 #[inline(always)]
80 pub fn is_negative(&self) -> bool {
81 self.0.is_negative()
82 }
83
84 pub fn integer_type(&self) -> IntegerDatatype {
85 if self.0 >= BigInt::zero() {
86 if self.0 > BigInt::zero() {
87 if self.0 <= *U8_MAX {
88 UnsignedShortDatatype::UnsignedByte.into()
89 } else if self.0 <= *U16_MAX {
90 UnsignedShortDatatype::UnsignedShort.into()
91 } else if self.0 <= *U32_MAX {
92 UnsignedIntDatatype::UnsignedInt.into()
93 } else if self.0 <= *U64_MAX {
94 UnsignedLongDatatype::UnsignedLong.into()
95 } else {
96 NonNegativeIntegerDatatype::PositiveInteger.into()
97 }
98 } else {
99 UnsignedShortDatatype::UnsignedByte.into()
100 }
101 } else if self.0 >= *I8_MIN {
102 ShortDatatype::Byte.into()
103 } else if self.0 >= *I16_MIN {
104 ShortDatatype::Short.into()
105 } else if self.0 >= *I32_MIN {
106 IntDatatype::Int.into()
107 } else if self.0 >= *I64_MIN {
108 LongDatatype::Long.into()
109 } else {
110 NonPositiveIntegerDatatype::NegativeInteger.into()
111 }
112 }
113
114 #[inline(always)]
116 pub fn lexical_representation(&self) -> lexical::IntegerBuf {
117 unsafe {
118 lexical::IntegerBuf::new_unchecked(format!("{}", self))
121 }
122 }
123
124 pub fn to_bytes_be(&self) -> (Sign, Vec<u8>) {
125 self.0.to_bytes_be()
126 }
127
128 pub fn to_bytes_le(&self) -> (Sign, Vec<u8>) {
129 self.0.to_bytes_le()
130 }
131
132 pub fn to_signed_bytes_be(&self) -> Vec<u8> {
133 self.0.to_signed_bytes_be()
134 }
135
136 pub fn to_signed_bytes_le(&self) -> Vec<u8> {
137 self.0.to_signed_bytes_le()
138 }
139}
140
141impl XsdValue for Integer {
142 #[inline(always)]
143 fn datatype(&self) -> Datatype {
144 self.integer_type().into()
145 }
146}
147
148impl ParseXsd for Integer {
149 type LexicalForm = lexical::Integer;
150}
151
152impl LexicalFormOf<Integer> for lexical::Integer {
153 type ValueError = std::convert::Infallible;
154
155 fn try_as_value(&self) -> Result<Integer, Self::ValueError> {
156 Ok(self.value())
157 }
158}
159
160impl From<BigInt> for Integer {
161 #[inline(always)]
162 fn from(value: BigInt) -> Self {
163 Self(value)
164 }
165}
166
167impl From<Integer> for BigInt {
168 #[inline(always)]
169 fn from(value: Integer) -> Self {
170 value.0
171 }
172}
173
174impl<'a> From<&'a lexical::Integer> for Integer {
175 #[inline(always)]
176 fn from(value: &'a lexical::Integer) -> Self {
177 Self(value.as_str().parse().unwrap())
178 }
179}
180
181impl From<lexical::IntegerBuf> for Integer {
182 #[inline(always)]
183 fn from(value: lexical::IntegerBuf) -> Self {
184 value.as_integer().into()
185 }
186}
187
188impl FromStr for Integer {
189 type Err = lexical::InvalidInteger;
190
191 #[inline(always)]
192 fn from_str(s: &str) -> Result<Self, Self::Err> {
193 let l = lexical::Integer::new(s)?;
194 Ok(l.into())
195 }
196}
197
198impl From<lexical::NonPositiveIntegerBuf> for Integer {
199 #[inline(always)]
200 fn from(value: lexical::NonPositiveIntegerBuf) -> Self {
201 value.as_integer().into()
202 }
203}
204
205impl From<NonNegativeInteger> for Integer {
206 fn from(value: NonNegativeInteger) -> Self {
207 let n: BigInt = value.into();
208 Self(n)
209 }
210}
211
212impl fmt::Display for Integer {
213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
214 self.0.fmt(f)
215 }
216}
217
218impl AsRef<BigInt> for Integer {
219 #[inline(always)]
220 fn as_ref(&self) -> &BigInt {
221 &self.0
222 }
223}
224
225impl Borrow<BigInt> for Integer {
226 #[inline(always)]
227 fn borrow(&self) -> &BigInt {
228 &self.0
229 }
230}
231
232#[derive(Debug, thiserror::Error)]
233#[error("integer out of supported bounds: {0}")]
234pub struct IntegerOutOfTargetBounds(pub Integer);
235
236macro_rules! from {
237 { $( $ty:ty ),* } => {
238 $(
239 impl From<$ty> for Integer {
240 fn from(value: $ty) -> Self {
241 Self(value.into())
242 }
243 }
244 )*
245 };
246}
247
248from!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
249
250macro_rules! try_into {
251 { $( $ty:ty ),* } => {
252 $(
253 impl TryFrom<Integer> for $ty {
254 type Error = IntegerOutOfTargetBounds;
255
256 fn try_from(value: Integer) -> Result<Self, Self::Error> {
257 value.0.try_into().map_err(|e: TryFromBigIntError<BigInt>| IntegerOutOfTargetBounds(Integer(e.into_original())))
258 }
259 }
260
261 impl<'a> TryFrom<&'a Integer> for $ty {
262 type Error = IntegerOutOfTargetBounds;
263
264 fn try_from(value: &'a Integer) -> Result<Self, Self::Error> {
265 value.0.clone().try_into().map_err(|e: TryFromBigIntError<BigInt>| IntegerOutOfTargetBounds(Integer(e.into_original()))) }
267 }
268 )*
269 };
270}
271
272try_into!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
273
274pub type Long = i64;
275
276pub trait XsdLong {
277 fn long_type(&self) -> LongDatatype;
278}
279
280impl XsdLong for Long {
281 fn long_type(&self) -> LongDatatype {
282 if (i8::MIN as i64..=i8::MAX as i64).contains(self) {
283 ShortDatatype::Byte.into()
284 } else if (i16::MIN as i64..=i16::MAX as i64).contains(self) {
285 ShortDatatype::Short.into()
286 } else if (i32::MIN as i64..=i32::MAX as i64).contains(self) {
287 IntDatatype::Int.into()
288 } else {
289 LongDatatype::Long
290 }
291 }
292}
293
294impl XsdValue for Long {
295 fn datatype(&self) -> Datatype {
296 self.long_type().into()
297 }
298}
299
300impl ParseXsd for Long {
301 type LexicalForm = lexical::Integer;
302}
303
304impl LexicalFormOf<Long> for lexical::Integer {
305 type ValueError = IntegerOutOfTargetBounds;
306
307 fn try_as_value(&self) -> Result<Long, Self::ValueError> {
308 self.value().try_into()
309 }
310}
311
312pub type Int = i32;
313
314pub trait XsdInt {
315 fn int_type(&self) -> IntDatatype;
316}
317
318impl XsdInt for Int {
319 fn int_type(&self) -> IntDatatype {
320 if (i8::MIN as i32..=i8::MAX as i32).contains(self) {
321 ShortDatatype::Byte.into()
322 } else if (i16::MIN as i32..=i16::MAX as i32).contains(self) {
323 ShortDatatype::Short.into()
324 } else {
325 IntDatatype::Int
326 }
327 }
328}
329
330impl XsdValue for Int {
331 fn datatype(&self) -> Datatype {
332 self.int_type().into()
333 }
334}
335
336impl ParseXsd for Int {
337 type LexicalForm = lexical::Integer;
338}
339
340impl LexicalFormOf<Int> for lexical::Integer {
341 type ValueError = IntegerOutOfTargetBounds;
342
343 fn try_as_value(&self) -> Result<Int, Self::ValueError> {
344 self.value().try_into()
345 }
346}
347
348pub type Short = i16;
349
350pub trait XsdShort {
351 fn short_type(&self) -> ShortDatatype;
352}
353
354impl XsdShort for Short {
355 fn short_type(&self) -> ShortDatatype {
356 if (i8::MIN as i16..=i8::MAX as i16).contains(self) {
357 ShortDatatype::Byte
358 } else {
359 ShortDatatype::Short
360 }
361 }
362}
363
364impl XsdValue for Short {
365 fn datatype(&self) -> Datatype {
366 self.short_type().into()
367 }
368}
369
370impl ParseXsd for Short {
371 type LexicalForm = lexical::Integer;
372}
373
374impl LexicalFormOf<Short> for lexical::Integer {
375 type ValueError = IntegerOutOfTargetBounds;
376
377 fn try_as_value(&self) -> Result<Short, Self::ValueError> {
378 self.value().try_into()
379 }
380}
381
382pub type Byte = i8;
383
384impl XsdValue for Byte {
385 fn datatype(&self) -> Datatype {
386 ShortDatatype::Byte.into()
387 }
388}
389
390impl ParseXsd for Byte {
391 type LexicalForm = lexical::Integer;
392}
393
394impl LexicalFormOf<Byte> for lexical::Integer {
395 type ValueError = IntegerOutOfTargetBounds;
396
397 fn try_as_value(&self) -> Result<Byte, Self::ValueError> {
398 self.value().try_into()
399 }
400}
401
402macro_rules! impl_integer_arithmetic {
403 {
404 for $target:ty where $id:ident ( $test:expr ) {
405 $( $ty:ty $([$($accessor:tt)*])? ),*
406 }
407 } => {
408 $(
409 impl Add<$ty> for $target {
410 type Output = Self;
411
412 fn add(self, rhs: $ty) -> Self::Output {
413 let $id = self.0 + rhs $($($accessor)*)?;
414
415 if !($test) {
416 panic!("attempt to add with overflow")
417 }
418
419 Self($id)
420 }
421 }
422
423 impl Sub<$ty> for $target {
424 type Output = Self;
425
426 fn sub(self, rhs: $ty) -> Self::Output {
427 let $id = self.0 - rhs $($($accessor)*)?;
428
429 if !($test) {
430 panic!("attempt to subtract with overflow")
431 }
432
433 Self($id)
434 }
435 }
436
437 impl Mul<$ty> for $target {
438 type Output = Self;
439
440 fn mul(self, rhs: $ty) -> Self::Output {
441 let $id = self.0 * rhs $($($accessor)*)?;
442
443 if !($test) {
444 panic!("attempt to multiply with overflow")
445 }
446
447 Self($id)
448 }
449 }
450
451 impl Div<$ty> for $target {
452 type Output = Self;
453
454 fn div(self, rhs: $ty) -> Self::Output {
455 let $id = self.0 / rhs $($($accessor)*)?;
456
457 if !($test) {
458 panic!("attempt to divide with overflow")
459 }
460
461 Self($id)
462 }
463 }
464 )*
465 };
466}
467
468pub(crate) use impl_integer_arithmetic;
469
470impl_integer_arithmetic! {
471 for Integer where r (true) {
472 Integer [.0], i8, i16, i32, i64, isize, u8, u16, u32, u64, usize
473 }
474}