1#![expect(
4 clippy::arbitrary_source_item_ordering,
5 reason = "macros must be defined before they're used"
6)]
7
8use {
9 crate::{
10 CanBeInfinite, Finite, Negative, NonNegative, NonPositive, NonZero, OnUnit, One, Positive,
11 Zero,
12 },
13 core::{
14 borrow::Borrow,
15 cmp::Ordering,
16 fmt,
17 hash::{Hash, Hasher},
18 marker::PhantomData,
19 ops,
20 },
21};
22
23#[cfg(test)]
24use {paste::paste, quickcheck::TestResult, quickcheck_macros::quickcheck};
25
26#[cfg(feature = "std")]
27use std::env;
28
29#[cfg(any(test, feature = "quickcheck"))]
30use quickcheck::{Arbitrary, Gen};
31
32#[cfg(all(any(test, feature = "quickcheck"), not(feature = "std")))]
33use alloc::boxed::Box;
34
35macro_rules! impl_op_1 {
37 ($op:ident, $fn:ident, $lhs:ident, $out:ident $(, $($bound:ident),* $(,)?)?) => {
38 impl<
39 L: $($($bound +)*)? fmt::Debug + ops::$op<Output: $($($bound +)*)? fmt::Debug>,
40 > ops::$op for $lhs<L>
41 {
42 type Output = $out<<L as ops::$op>::Output>;
43
44 #[inline]
45 fn $fn(self) -> Self::Output {
46 self.map(|lhs| lhs.$fn())
47 }
48 }
49
50 #[cfg(test)]
51 paste! {
52 #[cfg(test)]
53 #[expect(trivial_casts, clippy::as_conversions, reason = "must be an implementation detail of `quickcheck`")]
54 mod [< $lhs:snake _ $fn >] {
55 use super::*;
56
57 #[quickcheck]
58 fn doesnt_panic(lhs: $lhs<f64>) -> TestResult {
59 if lhs.abs() > 1e64_f64 { return TestResult::discard() }
60 _ = <$lhs<f64> as ops::$op>::$fn(lhs);
61 TestResult::passed()
62 }
63 }
64 }
65 };
66}
67
68macro_rules! impl_op_2 {
70 ($op:ident, $fn:ident, $lhs:ident, $rhs:ident, $out:ident, $reject:expr $(, $($bound:ident),* $(,)?)?) => {
71 impl<
72 L: $($($bound +)*)? fmt::Debug + ops::$op<R, Output: $($($bound +)*)? fmt::Debug>,
73 R: $($($bound +)*)? fmt::Debug,
74 > ops::$op<$rhs<R>> for $lhs<L>
75 {
76 type Output = $out<<L as ops::$op<R>>::Output>;
77
78 #[inline]
79 fn $fn(self, rhs: $rhs<R>) -> Self::Output {
80 self.map(|lhs| lhs.$fn(rhs.get()))
81 }
82 }
83
84 #[cfg(test)]
85 paste! {
86 #[cfg(test)]
87 #[expect(trivial_casts, clippy::as_conversions, reason = "must be an implementation detail of `quickcheck`")]
88 mod [< $lhs:snake _ $fn _ $rhs:snake >] {
89 use super::*;
90
91 #[quickcheck]
92 fn doesnt_panic(lhs: $lhs<f64>, rhs: $rhs<f64>) -> TestResult {
93 if lhs.abs() > 1e64_f64 { return TestResult::discard() }
94 if rhs.abs() > 1e64_f64 { return TestResult::discard() }
95 let toss: fn(&$lhs<f64>, &$rhs<f64>) -> bool = $reject;
96 if toss(&lhs, &rhs) { return TestResult::discard() }
97 _ = <$lhs<f64> as ops::$op<$rhs<f64>>>::$fn(lhs, rhs);
98 TestResult::passed()
99 }
100 }
101 }
102
103 impl<
104 'rhs,
105 L: $($($bound +)*)? fmt::Debug + ops::$op<&'rhs R, Output: $($($bound +)*)? fmt::Debug>,
106 R: $($($bound +)*)? fmt::Debug,
107 > ops::$op<&'rhs $rhs<R>> for $lhs<L>
108 {
109 type Output = $out<<L as ops::$op<&'rhs R>>::Output>;
110
111 #[inline]
112 fn $fn(self, rhs: &'rhs $rhs<R>) -> Self::Output {
113 self.map(|lhs| lhs.$fn(rhs.get_ref()))
114 }
115 }
116
117 #[cfg(test)]
118 paste! {
119 #[cfg(test)]
120 #[expect(trivial_casts, clippy::as_conversions, reason = "must be an implementation detail of `quickcheck`")]
121 mod [< $lhs:snake _ $fn _ $rhs:snake _ref >] {
122 use super::*;
123
124 #[quickcheck]
125 fn doesnt_panic(lhs: $lhs<f64>, rhs: $rhs<f64>) -> TestResult {
126 if lhs.abs() > 1e64_f64 { return TestResult::discard() }
127 if rhs.abs() > 1e64_f64 { return TestResult::discard() }
128 let toss: fn(&$lhs<f64>, &$rhs<f64>) -> bool = $reject;
129 if toss(&lhs, &rhs) { return TestResult::discard() }
130 _ = <$lhs<f64> as ops::$op<&$rhs<f64>>>::$fn(lhs, &rhs);
131 TestResult::passed()
132 }
133 }
134 }
135
136 };
187}
188
189macro_rules! impl_op_assign {
191 ($op:ident, $fn:ident, $lhs:ident, $rhs:ident, $reject:expr $(, $($bound:ident),* $(,)?)?) => {
192 impl<
193 L: $($($bound +)*)? fmt::Debug + ops::$op<R>,
194 R: $($($bound +)*)? fmt::Debug,
195 > ops::$op<$rhs<R>> for $lhs<L>
196 {
197 #[inline]
198 fn $fn(&mut self, rhs: $rhs<R>) {
199 self.map_mut(|lhs| lhs.$fn(rhs.get()))
200 }
201 }
202
203 #[cfg(test)]
204 paste! {
205 #[cfg(test)]
206 #[expect(trivial_casts, clippy::as_conversions, reason = "must be an implementation detail of `quickcheck`")]
207 mod [< $lhs:snake _ $fn _ $rhs:snake >] {
208 use super::*;
209
210 #[quickcheck]
211 fn doesnt_panic(mut lhs: $lhs<f64>, rhs: $rhs<f64>) -> TestResult {
212 if lhs.abs() > 1e64_f64 { return TestResult::discard() }
213 if rhs.abs() > 1e64_f64 { return TestResult::discard() }
214 let toss: fn(&$lhs<f64>, &$rhs<f64>) -> bool = $reject;
215 if toss(&lhs, &rhs) { return TestResult::discard() }
216 _ = <$lhs<f64> as ops::$op<$rhs<f64>>>::$fn(&mut lhs, rhs);
217 TestResult::passed()
218 }
219 }
220 }
221
222 impl<
223 'rhs,
224 L: $($($bound +)*)? fmt::Debug + ops::$op<&'rhs R>,
225 R: $($($bound +)*)? fmt::Debug,
226 > ops::$op<&'rhs $rhs<R>> for $lhs<L>
227 {
228 #[inline]
229 fn $fn(&mut self, rhs: &'rhs $rhs<R>) {
230 self.map_mut(|lhs| lhs.$fn(rhs.get_ref()))
231 }
232 }
233
234 #[cfg(test)]
235 paste! {
236 #[cfg(test)]
237 #[expect(trivial_casts, clippy::as_conversions, reason = "must be an implementation detail of `quickcheck`")]
238 mod [< $lhs:snake _ $fn _ $rhs:snake _ref >] {
239 use super::*;
240
241 #[quickcheck]
242 fn doesnt_panic(mut lhs: $lhs<f64>, rhs: $rhs<f64>) -> TestResult {
243 if lhs.abs() > 1e64_f64 { return TestResult::discard() }
244 if rhs.abs() > 1e64_f64 { return TestResult::discard() }
245 let toss: fn(&$lhs<f64>, &$rhs<f64>) -> bool = $reject;
246 if toss(&lhs, &rhs) { return TestResult::discard() }
247 _ = <$lhs<f64> as ops::$op<&$rhs<f64>>>::$fn(&mut lhs, &rhs);
248 TestResult::passed()
249 }
250 }
251 }
252 };
253}
254
255macro_rules! impl_add {
257 ($lhs:ident, $rhs:ident, $out:ident $(, $($bound:ident),* $(,)?)?) => {
258 impl_op_2!(Add, add, $lhs, $rhs, $out, |_, _| false $(, $($bound,)*)?);
259 impl_op_assign!(AddAssign, add_assign, $lhs, $rhs, |_, _| false $(, $($bound,)*)?);
260 };
261}
262
263macro_rules! impl_sub {
265 ($lhs:ident, $rhs:ident, $out:ident $(, $($bound:ident),* $(,)?)?) => {
266 impl_op_2!(Sub, sub, $lhs, $rhs, $out, |_, _| false $(, $($bound,)*)?);
267 impl_op_assign!(SubAssign, sub_assign, $lhs, $rhs, |_, _| false $(, $($bound,)*)?);
268 };
269}
270
271macro_rules! impl_mul {
273 ($lhs:ident, $rhs:ident, $out:ident $(, $($bound:ident),* $(,)?)?) => {
274 impl_op_2!(Div, div, $lhs, $rhs, $out, |_, rhs| rhs.get() == 0_f64 $(, $($bound,)*)?);
275 impl_op_2!(Mul, mul, $lhs, $rhs, $out, |_, _| false $(, $($bound,)*)?);
276 };
277}
278
279macro_rules! impl_mul_assign {
281 ($lhs:ident, $rhs:ident $(, $($bound:ident),* $(,)?)?) => {
282 impl_op_assign!(DivAssign, div_assign, $lhs, $rhs, |_, rhs| rhs.get() == 0_f64 $(, $($bound,)*)?);
283 impl_op_assign!(MulAssign, mul_assign, $lhs, $rhs, |_, _| false $(, $($bound,)*)?);
284 };
285}
286
287impl<Z: CanBeInfinite + One + fmt::Debug> One for Finite<Z> {
288 const ONE: Self = Self {
289 phantom: PhantomData,
290 raw: Z::ONE,
291 };
292}
293
294impl<Z: CanBeInfinite + Zero + fmt::Debug> Zero for Finite<Z> {
295 const ZERO: Self = Self {
296 phantom: PhantomData,
297 raw: Z::ZERO,
298 };
299}
300
301impl_add!(Finite, Finite, Finite, CanBeInfinite);
302impl_sub!(Finite, Finite, Finite, CanBeInfinite);
303impl_mul!(Finite, Finite, Finite, CanBeInfinite);
304impl_mul_assign!(Finite, Finite, CanBeInfinite);
305impl_op_1!(Neg, neg, Finite, Finite, CanBeInfinite);
306
307impl_add!(Negative, Negative, Negative, PartialOrd, Zero);
308impl_sub!(Negative, NonNegative, Negative, PartialOrd, Zero);
309impl_add!(Negative, NonPositive, Negative, PartialOrd, Zero);
310impl_sub!(Negative, Positive, Negative, PartialOrd, Zero);
311impl_mul!(Negative, Negative, Positive, PartialOrd, Zero);
312impl_mul!(Negative, NonNegative, NonPositive, PartialOrd, Zero);
313impl_mul!(Negative, NonPositive, NonNegative, PartialOrd, Zero);
314impl_mul!(Negative, Positive, Negative, PartialOrd, Zero);
315impl_mul_assign!(Negative, Positive, PartialOrd, Zero);
316impl_op_1!(Neg, neg, Negative, Positive, PartialOrd, Zero);
317
318impl<T: One + PartialOrd + Zero + fmt::Debug> One for NonNegative<T> {
319 const ONE: Self = Self {
320 phantom: PhantomData,
321 raw: T::ONE,
322 };
323}
324
325impl<Z: PartialOrd + Zero + fmt::Debug> Zero for NonNegative<Z> {
326 const ZERO: Self = Self {
327 phantom: PhantomData,
328 raw: Z::ZERO,
329 };
330}
331
332impl_sub!(NonNegative, Negative, Positive, PartialOrd, Zero);
333impl_add!(NonNegative, NonNegative, NonNegative, PartialOrd, Zero);
334impl_sub!(NonNegative, NonPositive, NonNegative, PartialOrd, Zero);
335impl_add!(NonNegative, Positive, Positive, PartialOrd, Zero);
336impl_mul!(NonNegative, Negative, NonPositive, PartialOrd, Zero);
337impl_mul!(NonNegative, NonNegative, NonNegative, PartialOrd, Zero);
338impl_mul!(NonNegative, NonPositive, NonPositive, PartialOrd, Zero);
339impl_mul!(NonNegative, Positive, NonNegative, PartialOrd, Zero);
340impl_mul_assign!(NonNegative, NonNegative, PartialOrd, Zero);
341impl_mul_assign!(NonNegative, Positive, PartialOrd, Zero);
342impl_op_1!(Neg, neg, NonNegative, NonPositive, PartialOrd, Zero);
343
344impl_add!(NonPositive, Negative, Negative, PartialOrd, Zero);
345impl_sub!(NonPositive, NonNegative, NonPositive, PartialOrd, Zero);
346impl_add!(NonPositive, NonPositive, NonPositive, PartialOrd, Zero);
347impl_sub!(NonPositive, Positive, Negative, PartialOrd, Zero);
348impl_mul!(NonPositive, Negative, NonNegative, PartialOrd, Zero);
349impl_mul!(NonPositive, NonNegative, NonPositive, PartialOrd, Zero);
350impl_mul!(NonPositive, NonPositive, NonNegative, PartialOrd, Zero);
351impl_mul!(NonPositive, Positive, NonPositive, PartialOrd, Zero);
352impl_mul_assign!(NonPositive, NonNegative, PartialOrd, Zero);
353impl_mul_assign!(NonPositive, Positive, PartialOrd, Zero);
354impl_op_1!(Neg, neg, NonPositive, NonNegative, PartialOrd, Zero);
355
356impl_mul!(NonZero, NonZero, NonZero, PartialEq, Zero);
357impl_op_1!(Neg, neg, NonZero, NonZero, PartialEq, Zero);
358
359impl<T: One + PartialOrd + Zero + fmt::Debug, const INCLUSIVE_AT_ZERO: bool> One
360 for OnUnit<T, INCLUSIVE_AT_ZERO, true>
361{
362 const ONE: Self = Self {
363 phantom: PhantomData,
364 raw: T::ONE,
365 };
366}
367
368impl<Z: One + PartialOrd + Zero + fmt::Debug, const INCLUSIVE_AT_ONE: bool> Zero
369 for OnUnit<Z, true, INCLUSIVE_AT_ONE>
370{
371 const ZERO: Self = Self {
372 phantom: PhantomData,
373 raw: Z::ZERO,
374 };
375}
376
377impl_sub!(Positive, Negative, Positive, PartialOrd, Zero);
378impl_add!(Positive, NonNegative, Positive, PartialOrd, Zero);
379impl_sub!(Positive, NonPositive, Positive, PartialOrd, Zero);
380impl_add!(Positive, Positive, Positive, PartialOrd, Zero);
381impl_mul!(Positive, Negative, Negative, PartialOrd, Zero);
382impl_mul!(Positive, NonNegative, NonNegative, PartialOrd, Zero);
383impl_mul!(Positive, NonPositive, NonPositive, PartialOrd, Zero);
384impl_mul!(Positive, Positive, Positive, PartialOrd, Zero);
385impl_mul_assign!(Positive, Positive, PartialOrd, Zero);
386impl_op_1!(Neg, neg, Positive, Negative, PartialOrd, Zero);
387
388impl<T: One + PartialOrd + Zero + fmt::Debug> One for Positive<T> {
389 const ONE: Self = Self {
390 phantom: PhantomData,
391 raw: T::ONE,
392 };
393}
394
395impl<Raw: fmt::Debug, Invariant: crate::Test<Raw, 1>> From<Raw> for Sigma<Raw, Invariant> {
396 #[inline(always)]
397 fn from(value: Raw) -> Self {
398 Self::new(value)
399 }
400}
401
402#[repr(transparent)]
404pub struct Sigma<Raw: fmt::Debug, Invariant: crate::Test<Raw, 1>> {
405 phantom: PhantomData<Invariant>,
407 raw: Raw,
409}
410
411impl<Raw: fmt::Debug, Invariant: crate::Test<Raw, 1>> Sigma<Raw, Invariant> {
412 #[inline]
414 pub fn all<const N: usize>(array: &[Raw; N]) -> &[Self; N] {
415 let pointer: *const [Raw; N] = array;
416 let cast: *const [Self; N] = pointer.cast();
417 let provisional = unsafe { &*cast };
420 for element in provisional {
421 element.check();
422 }
423 provisional
424 }
425
426 #[inline(always)]
432 pub fn also<OtherInvariant: crate::Test<Raw, 1>>(self) -> Sigma<Raw, OtherInvariant> {
433 Sigma::new(self.get())
434 }
435
436 #[inline]
442 #[cfg(debug_assertions)]
443 pub fn also_ref<OtherInvariant: crate::Test<Raw, 1>>(&self) -> &Sigma<Raw, OtherInvariant> {
444 let ptr: *const Self = self;
445 let transmuted: &Sigma<Raw, OtherInvariant> = unsafe { &*ptr.cast() };
449 transmuted.check();
450 transmuted
451 }
452
453 #[inline]
457 #[cfg(not(debug_assertions))]
458 pub const fn also_ref<OtherInvariant: crate::Test<Raw, 1>>(
459 &self,
460 ) -> &Sigma<Raw, OtherInvariant> {
461 let ptr: *const Self = self;
462 unsafe { &*ptr.cast() }
466 }
467
468 #[inline]
472 #[cfg(debug_assertions)]
473 pub fn check(&self) {
474 #[expect(
475 clippy::panic,
476 reason = "Returning a result would break API in release builds"
477 )]
478 match Invariant::test([&self.raw]) {
479 Ok(()) => {}
480 Err(message) => {
481 panic!("{:#?} is not {}: {message}", self.raw, Invariant::ADJECTIVE);
482 }
483 }
484 }
485
486 #[inline]
488 #[cfg(not(debug_assertions))]
489 pub const fn check(&self) {}
490
491 #[inline(always)]
495 pub fn get(self) -> Raw {
496 self.raw
497 }
498
499 #[inline(always)]
503 #[expect(clippy::allow_attributes, reason = "Edition 2021 only")]
504 #[allow(tail_expr_drop_order, reason = "just for miri")]
505 pub fn get_by<Y, F: FnOnce(Raw) -> Y>(self, f: F) -> Y {
506 f(self.get())
507 }
508
509 #[inline(always)]
513 pub fn get_by_mut<Y, F: FnOnce(&mut Raw) -> Y>(&mut self, f: F) -> Y {
514 f(self.get_mut())
515 }
516
517 #[inline(always)]
521 pub fn get_by_ref<Y, F: FnOnce(&Raw) -> Y>(&self, f: F) -> Y {
522 f(self)
523 }
524
525 #[inline(always)]
529 pub const fn get_mut(&mut self) -> &mut Raw {
530 &mut self.raw
531 }
532
533 #[inline(always)]
537 pub const fn get_ref(&self) -> &Raw {
538 &self.raw
539 }
540
541 #[inline]
544 #[expect(clippy::allow_attributes, reason = "Edition 2021 only")]
545 #[allow(tail_expr_drop_order, reason = "just for miri")]
546 pub fn map<
547 OtherRaw: fmt::Debug,
548 OtherInvariant: crate::Test<OtherRaw, 1>,
549 F: FnOnce(Raw) -> OtherRaw,
550 >(
551 self,
552 f: F,
553 ) -> Sigma<OtherRaw, OtherInvariant> {
554 Sigma::new(f(self.get()))
555 }
556
557 #[inline]
560 pub fn map_mut<Y, F: FnOnce(&mut Raw) -> Y>(&mut self, f: F) -> Y {
561 let raw = self.get_mut();
562 let y = f(raw);
563 self.check();
564 y
565 }
566
567 #[inline]
570 #[expect(clippy::allow_attributes, reason = "Edition 2021 only")]
571 #[allow(tail_expr_drop_order, reason = "just for miri")]
572 pub fn map_ref<
573 OtherRaw: fmt::Debug,
574 OtherInvariant: crate::Test<OtherRaw, 1>,
575 F: FnOnce(&Raw) -> OtherRaw,
576 >(
577 &self,
578 f: F,
579 ) -> Sigma<OtherRaw, OtherInvariant> {
580 Sigma::new(f(self))
581 }
582
583 #[inline]
587 #[cfg(debug_assertions)]
588 pub fn new(raw: Raw) -> Self {
589 let provisional = Self {
590 phantom: PhantomData,
591 raw,
592 };
593 provisional.check();
594 provisional
595 }
596
597 #[inline]
601 #[cfg(not(debug_assertions))]
602 pub const fn new(raw: Raw) -> Self {
603 Self {
604 phantom: PhantomData,
605 raw,
606 }
607 }
608
609 #[inline]
615 pub fn try_also<OtherInvariant: crate::Test<Raw, 1>>(
616 self,
617 ) -> Result<Sigma<Raw, OtherInvariant>, Self> {
618 Sigma::try_new(self.get()).map_err(|raw| Self {
619 phantom: PhantomData,
620 raw,
621 })
622 }
623
624 #[inline]
630 pub fn try_also_ref<OtherInvariant: crate::Test<Raw, 1>>(
631 &self,
632 ) -> Result<&Sigma<Raw, OtherInvariant>, OtherInvariant::Error<'_>> {
633 let ptr: *const Self = self;
634 let transmuted: &Sigma<Raw, OtherInvariant> = unsafe { &*ptr.cast() };
638 transmuted.try_check()?;
639 Ok(transmuted)
640 }
641
642 #[inline(always)]
646 pub fn try_check(&self) -> Result<(), Invariant::Error<'_>> {
647 Invariant::test([&self.raw])
648 }
649
650 #[inline]
655 pub fn try_new(raw: Raw) -> Result<Self, Raw> {
656 let provisional = Self {
657 phantom: PhantomData,
658 raw,
659 };
660
661 if provisional.try_check().is_ok() {
662 Ok(provisional)
663 } else {
664 Err(provisional.raw)
665 }
666 }
667
668 #[inline(always)]
670 #[cfg(debug_assertions)]
671 pub fn wrap(reference: &Raw) -> &Self {
672 let raw_pointer: *const _ = reference;
673 let sigma_pointer = raw_pointer.cast::<Self>();
674 let wrapped = unsafe { &*sigma_pointer };
677 wrapped.check();
678 wrapped
679 }
680
681 #[inline(always)]
683 #[cfg(not(debug_assertions))]
684 pub const fn wrap(reference: &Raw) -> &Self {
685 let raw_pointer: *const _ = reference;
686 let sigma_pointer = raw_pointer.cast::<Self>();
687 unsafe { &*sigma_pointer }
690 }
691
692 #[inline(always)]
694 pub fn wrap_mut(reference: &mut Raw) -> &mut Self {
695 let raw_pointer: *mut _ = reference;
696 let sigma_pointer = raw_pointer.cast::<Self>();
697 let wrapped = unsafe { &mut *sigma_pointer };
700 wrapped.check();
701 wrapped
702 }
703}
704
705#[cfg(any(test, feature = "quickcheck"))]
706impl<Raw: Arbitrary + fmt::Debug, Invariant: 'static + crate::Test<Raw, 1>> Arbitrary
707 for Sigma<Raw, Invariant>
708{
709 #[inline]
710 fn arbitrary(g: &mut Gen) -> Self {
711 loop {
712 let raw: Raw = Arbitrary::arbitrary(g);
713 if let Ok(sigma) = Self::try_new(raw) {
714 return sigma;
715 }
716 }
717 }
718
719 #[inline]
720 fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
721 let Self {
722 phantom: PhantomData,
723 ref raw,
724 } = *self;
725 Box::new(raw.shrink().filter_map(|shrunk| Self::try_new(shrunk).ok()))
726 }
727}
728
729impl<Raw: fmt::Debug, Invariant: crate::Test<Raw, 1>> AsRef<Raw> for Sigma<Raw, Invariant> {
730 #[inline(always)]
731 fn as_ref(&self) -> &Raw {
732 &self.raw
733 }
734}
735
736impl<Raw: fmt::Debug, Invariant: crate::Test<Raw, 1>> Borrow<Raw> for Sigma<Raw, Invariant> {
737 #[inline(always)]
738 fn borrow(&self) -> &Raw {
739 &self.raw
740 }
741}
742
743impl<Raw: CanBeInfinite + fmt::Debug, Invariant: crate::Test<Raw>> CanBeInfinite
744 for Sigma<Raw, Invariant>
745{
746 #[inline(always)]
747 fn check_finite(&self) -> bool {
748 self.raw.check_finite()
749 }
750}
751
752impl<Raw: Clone + fmt::Debug, Invariant: crate::Test<Raw, 1>> Clone for Sigma<Raw, Invariant> {
753 #[inline(always)]
754 fn clone(&self) -> Self {
755 Self::new(self.raw.clone())
756 }
757
758 #[inline(always)]
759 fn clone_from(&mut self, source: &Self) {
760 self.raw.clone_from(&source.raw);
761 self.check();
762 }
763}
764
765impl<Raw: Copy + fmt::Debug, Invariant: crate::Test<Raw, 1>> Copy for Sigma<Raw, Invariant> {}
766
767impl<Raw: Default + fmt::Debug, Invariant: crate::Test<Raw, 1>> Default for Sigma<Raw, Invariant> {
768 #[inline(always)]
769 fn default() -> Self {
770 Self::new(Raw::default())
771 }
772}
773
774impl<Raw: Eq + fmt::Debug, Invariant: crate::Test<Raw, 1>> Eq for Sigma<Raw, Invariant> {
775 #[inline(always)]
776 fn assert_receiver_is_total_eq(&self) {
777 self.raw.assert_receiver_is_total_eq();
778 }
779}
780
781impl<I, Raw: FromIterator<I> + fmt::Debug, Invariant: crate::Test<Raw, 1>> FromIterator<I>
782 for Sigma<Raw, Invariant>
783{
784 #[inline]
785 fn from_iter<T: IntoIterator<Item = I>>(iter: T) -> Self {
786 Self::new(Raw::from_iter(iter))
787 }
788}
789
790impl<Raw: Hash + fmt::Debug, Invariant: crate::Test<Raw, 1>> Hash for Sigma<Raw, Invariant> {
791 #[inline(always)]
792 fn hash<H: Hasher>(&self, state: &mut H) {
793 self.raw.hash(state);
794 }
795
796 #[inline(always)]
797 fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) {
798 let ptr: *const [Self] = data;
799 #[expect(clippy::as_conversions, reason = "marked `repr(transparent)` above")]
800 let transparent = ptr as *const [Raw];
801 let reinterpreted: &[Raw] = unsafe { &*transparent };
804 Raw::hash_slice(reinterpreted, state);
805 }
806}
807
808impl<Raw: IntoIterator + fmt::Debug, Invariant: crate::Test<Raw, 1>> IntoIterator
809 for Sigma<Raw, Invariant>
810{
811 type IntoIter = <Raw as IntoIterator>::IntoIter;
812 type Item = <Raw as IntoIterator>::Item;
813
814 #[inline(always)]
815 fn into_iter(self) -> Self::IntoIter {
816 Raw::into_iter(self.get())
817 }
818}
819
820impl<Raw: Ord + fmt::Debug, Invariant: crate::Test<Raw, 1>> Ord for Sigma<Raw, Invariant> {
828 #[inline(always)]
829 fn clamp(self, min: Self, max: Self) -> Self {
830 Self::new(self.raw.clamp(min.raw, max.raw))
831 }
832
833 #[inline(always)]
834 fn cmp(&self, other: &Self) -> Ordering {
835 self.raw.cmp(&other.raw)
836 }
837
838 #[inline(always)]
839 fn max(self, other: Self) -> Self {
840 Self::new(self.raw.max(other.raw))
841 }
842
843 #[inline(always)]
844 fn min(self, other: Self) -> Self {
845 Self::new(self.raw.min(other.raw))
846 }
847}
848
849impl<Raw: PartialEq + fmt::Debug, Invariant: crate::Test<Raw, 1>> PartialEq
850 for Sigma<Raw, Invariant>
851{
852 #[inline(always)]
853 fn eq(&self, other: &Self) -> bool {
854 self.raw.eq(&other.raw)
855 }
856
857 #[inline(always)]
858 #[expect(
859 clippy::partialeq_ne_impl,
860 reason = "arbitrary choice between competing lints"
861 )]
862 fn ne(&self, other: &Self) -> bool {
863 self.raw.ne(&other.raw)
864 }
865}
866
867impl<Raw: PartialOrd + fmt::Debug, Invariant: crate::Test<Raw, 1>> PartialOrd
868 for Sigma<Raw, Invariant>
869{
870 #[inline(always)]
871 fn ge(&self, other: &Self) -> bool {
872 self.raw.ge(&other.raw)
873 }
874
875 #[inline(always)]
876 fn gt(&self, other: &Self) -> bool {
877 self.raw.gt(&other.raw)
878 }
879
880 #[inline(always)]
881 fn le(&self, other: &Self) -> bool {
882 self.raw.le(&other.raw)
883 }
884
885 #[inline(always)]
886 fn lt(&self, other: &Self) -> bool {
887 self.raw.lt(&other.raw)
888 }
889
890 #[inline(always)]
891 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
892 self.raw.partial_cmp(&other.raw)
893 }
894}
895
896impl<Raw: fmt::Debug, Invariant: crate::Test<Raw, 1>> fmt::Debug for Sigma<Raw, Invariant> {
897 #[inline(always)]
898 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
899 #[cfg(feature = "std")]
900 if env::var("DEBUG_SIGMA_TYPES").is_ok_and(|s| s != "0") {
901 write!(f, "({}) ", Invariant::ADJECTIVE)?;
902 }
903 fmt::Debug::fmt(&self.raw, f)
904 }
905}
906
907impl<Raw: fmt::Debug + fmt::Display, Invariant: crate::Test<Raw, 1>> fmt::Display
908 for Sigma<Raw, Invariant>
909{
910 #[inline(always)]
911 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
912 fmt::Display::fmt(&self.raw, f)
913 }
914}
915
916impl<Raw: fmt::Debug, Invariant: crate::Test<Raw, 1>> ops::Deref for Sigma<Raw, Invariant> {
917 type Target = Raw;
918
919 #[inline(always)]
920 fn deref(&self) -> &Self::Target {
921 &self.raw
922 }
923}
924
925#[cfg(feature = "serde")]
926#[expect(clippy::missing_trait_methods, reason = "I'm no expert")]
927impl<'de, Raw: fmt::Debug + serde::Deserialize<'de>, Invariant: crate::Test<Raw, 1>>
928 serde::Deserialize<'de> for Sigma<Raw, Invariant>
929{
930 #[inline]
931 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
932 use serde::de::Error;
933
934 let raw = Raw::deserialize(deserializer)?;
935 let provisional = Self {
936 phantom: PhantomData,
937 raw,
938 };
939 match provisional.try_check() {
940 Ok(()) => {}
941 Err(e) => return Err(Error::custom(e)),
942 }
943 Ok(provisional)
944 }
945}
946
947#[cfg(feature = "serde")]
948impl<Raw: fmt::Debug + serde::Serialize, Invariant: crate::Test<Raw, 1>> serde::Serialize
949 for Sigma<Raw, Invariant>
950{
951 #[inline(always)]
952 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
953 self.raw.serialize(serializer)
954 }
955}