fastnum/cast.rs
1use crate::doc;
2
3/// Unified trait for conversions between fastnum numeric types.
4///
5/// Cast is a total conversion: it never fails and does not return an error.
6/// Prefer `Cast` when the conversion is guaranteed to be correct by definition
7/// (e.g., widening with preserved value or sign/zero extension that cannot
8/// overflow).
9///
10/// If the conversion may go out of range or lose information (sign/high bits),
11/// use [`TryCast`] instead.
12///
13/// # Examples:
14///
15/// ```
16/// use fastnum::*;
17///
18/// let a = u128!(123);
19///
20/// // Lossless widening
21/// let b: U256 = a.cast();
22/// assert_eq!(u256!(123), b);
23/// ```
24///
25/// See also: [`TryCast`] for fallible conversions.
26pub trait Cast<T> {
27 /// Performs an infallible, value-preserving conversion.
28 ///
29 /// This method never fails. Use it for conversions that are known to be
30 /// safe and cannot overflow or lose information (e.g., widening).
31 ///
32 /// # Examples:
33 ///
34 /// ```
35 /// use fastnum::*;
36 ///
37 /// let x = u128!(123);
38 /// let y: U256 = x.cast();
39 /// assert_eq!(u256!(123), y);
40 /// ```
41 #[must_use = doc::must_use_op!()]
42 fn cast(self) -> T;
43}
44
45/// Fallible conversion between fastnum numeric types (akin to `TryFrom`, but
46/// for fastnum).
47///
48/// TryCast returns `Result<T, Error>`, where `Error` describes why the
49/// conversion failed (e.g., out-of-range for the target type or invalid sign
50/// conversion).
51///
52/// Use `TryCast` when:
53/// - the value may not fit into the target type (overflow/underflow);
54/// - information could be lost (e.g., negative to unsigned);
55/// - you need explicit error handling rather than silent truncation.
56///
57/// # Examples:
58///
59/// ```
60/// use fastnum::*;
61///
62/// // Successful conversion (value fits in the target type)
63/// let x = u256!(42);
64/// let y: U128 = x.try_cast().unwrap();
65/// assert_eq!(u128!(42), y);
66///
67/// // Failing conversion (negative to unsigned)
68/// let neg = i256!(-1);
69/// assert!(<I256 as TryCast<U64>>::try_cast(neg).is_err());
70/// ```
71///
72/// Tips:
73/// - If the conversion is always valid by design — prefer [`Cast`].
74/// - If range/sign must be checked — prefer `TryCast`.
75pub trait TryCast<T> {
76 /// The type returned in the event of a conversion error.
77 type Error;
78
79 /// Attempts to convert `self` into `T`, returning an error on failure.
80 ///
81 /// Use this method when the conversion may be lossy or out-of-range.
82 ///
83 /// # Examples:
84 ///
85 /// ```
86 /// use fastnum::*;
87 ///
88 /// // In-range: succeeds
89 /// let a = u256!(18446744073709551615);
90 /// let b: U64 = a.try_cast().unwrap();
91 /// assert_eq!(u64!(18446744073709551615), b);
92 ///
93 /// // Out-of-range: fails with an error
94 /// let big = u256!(18446744073709551616);
95 /// let _ = <U256 as TryCast<U64>>::try_cast(big).unwrap_err();
96 /// ```
97 fn try_cast(self) -> Result<T, Self::Error>;
98}