xsd_types/value/decimal/
integer.rs

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/// Integer number.
27#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
28#[repr(transparent)]
29pub struct Integer(BigInt);
30
31impl Integer {
32	/// Converts a `BigInt` reference into an `Integer` reference.
33	#[inline(always)]
34	pub fn from_bigint_ref(n: &BigInt) -> &Self {
35		unsafe {
36			// This is safe because `Integer` is a transparent wrapper around
37			// `BigInt`.
38			std::mem::transmute(n)
39		}
40	}
41
42	/// Converts a `BigInt` into an `Integer`.
43	#[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	/// Returns a lexical representation of this integer.
115	#[inline(always)]
116	pub fn lexical_representation(&self) -> lexical::IntegerBuf {
117		unsafe {
118			// This is safe because the `Display::fmt` method matches the
119			// XSD lexical representation.
120			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()))) // TODO avoid cloning.
266				}
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}