Coverage Report

Created: 2026-04-12 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/num-conv-0.2.1/src/lib.rs
Line
Count
Source
1
//! `num_conv` is a crate to convert between integer types without using `as` casts. This provides
2
//! better certainty when refactoring, makes the exact behavior of code more explicit, and allows
3
//! using turbofish syntax.
4
5
#![no_std]
6
7
/// Anonymously import all extension traits.
8
///
9
/// This allows you to use the methods without worrying about polluting the namespace or importing
10
/// them individually.
11
///
12
/// ```rust
13
/// use num_conv::prelude::*;
14
/// ```
15
pub mod prelude {
16
    pub use crate::{Extend as _, Truncate as _};
17
}
18
19
mod sealed {
20
    pub trait Integer {}
21
22
    macro_rules! impl_integer {
23
        ($($t:ty)*) => {$(
24
            impl Integer for $t {}
25
        )*};
26
    }
27
28
    impl_integer! {
29
        u8 u16 u32 u64 u128 usize
30
        i8 i16 i32 i64 i128 isize
31
    }
32
33
    pub trait ExtendTargetSealed<T> {
34
        fn extend(self) -> T;
35
    }
36
37
    pub trait TruncateTargetSealed<T> {
38
        fn truncate(self) -> T;
39
        fn saturating_truncate(self) -> T;
40
        fn checked_truncate(self) -> Option<T>;
41
    }
42
}
43
44
/// A type that can be used with turbofish syntax in [`Extend::extend`].
45
///
46
/// It is unlikely that you will want to use this trait directly. You are probably looking for the
47
/// [`Extend`] trait.
48
pub trait ExtendTarget<T>: sealed::ExtendTargetSealed<T> {}
49
50
/// A type that can be used with turbofish syntax in [`Truncate::truncate`].
51
///
52
/// It is unlikely that you will want to use this trait directly. You are probably looking for the
53
/// [`Truncate`] trait.
54
pub trait TruncateTarget<T>: sealed::TruncateTargetSealed<T> {}
55
56
/// Extend to an integer of the same size or larger, preserving its value.
57
///
58
/// ```rust
59
/// # use num_conv::Extend;
60
/// assert_eq!(0_u8.extend::<u16>(), 0_u16);
61
/// assert_eq!(0_u16.extend::<u32>(), 0_u32);
62
/// assert_eq!(0_u32.extend::<u64>(), 0_u64);
63
/// assert_eq!(0_u64.extend::<u128>(), 0_u128);
64
/// ```
65
///
66
/// ```rust
67
/// # use num_conv::Extend;
68
/// assert_eq!((-1_i8).extend::<i16>(), -1_i16);
69
/// assert_eq!((-1_i16).extend::<i32>(), -1_i32);
70
/// assert_eq!((-1_i32).extend::<i64>(), -1_i64);
71
/// assert_eq!((-1_i64).extend::<i128>(), -1_i128);
72
/// ```
73
pub trait Extend: sealed::Integer {
74
    /// Extend an integer to an integer of the same size or larger, preserving its value.
75
    fn extend<T>(self) -> T
76
    where
77
        Self: ExtendTarget<T>;
78
}
79
80
impl<T: sealed::Integer> Extend for T {
81
38.2k
    fn extend<U>(self) -> U
82
38.2k
    where
83
38.2k
        T: ExtendTarget<U>,
84
    {
85
38.2k
        sealed::ExtendTargetSealed::extend(self)
86
38.2k
    }
<u8 as num_conv::Extend>::extend::<usize>
Line
Count
Source
81
10.7k
    fn extend<U>(self) -> U
82
10.7k
    where
83
10.7k
        T: ExtendTarget<U>,
84
    {
85
10.7k
        sealed::ExtendTargetSealed::extend(self)
86
10.7k
    }
<u8 as num_conv::Extend>::extend::<u32>
Line
Count
Source
81
7.93k
    fn extend<U>(self) -> U
82
7.93k
    where
83
7.93k
        T: ExtendTarget<U>,
84
    {
85
7.93k
        sealed::ExtendTargetSealed::extend(self)
86
7.93k
    }
Unexecuted instantiation: <u8 as num_conv::Extend>::extend::<u16>
<i16 as num_conv::Extend>::extend::<i32>
Line
Count
Source
81
19.5k
    fn extend<U>(self) -> U
82
19.5k
    where
83
19.5k
        T: ExtendTarget<U>,
84
    {
85
19.5k
        sealed::ExtendTargetSealed::extend(self)
86
19.5k
    }
Unexecuted instantiation: <u16 as num_conv::Extend>::extend::<usize>
Unexecuted instantiation: <u16 as num_conv::Extend>::extend::<u32>
87
}
88
89
/// Truncate to an integer of the same size or smaller.
90
///
91
/// Preserve the least significant bits with `.truncate()`:
92
///
93
/// ```rust
94
/// # use num_conv::Truncate;
95
/// assert_eq!(u16::MAX.truncate::<u8>(), u8::MAX);
96
/// assert_eq!(u32::MAX.truncate::<u16>(), u16::MAX);
97
/// assert_eq!(u64::MAX.truncate::<u32>(), u32::MAX);
98
/// assert_eq!(u128::MAX.truncate::<u64>(), u64::MAX);
99
/// ```
100
///
101
/// ```rust
102
/// # use num_conv::Truncate;
103
/// assert_eq!((-1_i16).truncate::<i8>(), -1_i8);
104
/// assert_eq!((-1_i32).truncate::<i16>(), -1_i16);
105
/// assert_eq!((-1_i64).truncate::<i32>(), -1_i32);
106
/// assert_eq!((-1_i128).truncate::<i64>(), -1_i64);
107
/// ```
108
///
109
/// Saturate to the numeric bounds with `.saturating_truncate()`:
110
///
111
/// ```rust
112
/// # use num_conv::Truncate;
113
/// assert_eq!(500_u16.saturating_truncate::<u8>(), u8::MAX);
114
/// assert_eq!(u32::MAX.saturating_truncate::<u16>(), u16::MAX);
115
/// assert_eq!(u64::MAX.saturating_truncate::<u32>(), u32::MAX);
116
/// assert_eq!(u128::MAX.saturating_truncate::<u64>(), u64::MAX);
117
/// ```
118
///
119
/// ```rust
120
/// # use num_conv::Truncate;
121
/// assert_eq!((-500_i16).saturating_truncate::<i8>(), i8::MIN);
122
/// assert_eq!(i32::MIN.saturating_truncate::<i16>(), i16::MIN);
123
/// assert_eq!(i64::MIN.saturating_truncate::<i32>(), i32::MIN);
124
/// assert_eq!(i128::MIN.saturating_truncate::<i64>(), i64::MIN);
125
/// ```
126
///
127
/// Checked with `.checked_truncate()`, returning `None` if the value is out of range:
128
///
129
/// ```rust
130
/// # use num_conv::Truncate;
131
/// assert_eq!(u16::MAX.checked_truncate::<u8>(), None);
132
/// assert_eq!(u32::MAX.checked_truncate::<u16>(), None);
133
/// assert_eq!(u64::MAX.checked_truncate::<u32>(), None);
134
/// assert_eq!(u128::MAX.checked_truncate::<u64>(), None);
135
/// ```
136
///
137
/// ```rust
138
/// # use num_conv::Truncate;
139
/// assert_eq!(i16::MIN.checked_truncate::<i8>(), None);
140
/// assert_eq!(i32::MIN.checked_truncate::<i16>(), None);
141
/// assert_eq!(i64::MIN.checked_truncate::<i32>(), None);
142
/// assert_eq!(i128::MIN.checked_truncate::<i64>(), None);
143
/// ```
144
pub trait Truncate: sealed::Integer {
145
    /// Truncate an integer to an integer of the same size or smaller, preserving the least
146
    /// significant bits.
147
    fn truncate<T>(self) -> T
148
    where
149
        Self: TruncateTarget<T>;
150
151
    /// Truncate an integer to an integer of the same size or smaller, saturating to the numeric
152
    /// bounds instead of wrapping.
153
    fn saturating_truncate<T>(self) -> T
154
    where
155
        Self: TruncateTarget<T>;
156
157
    /// Truncate an integer to an integer of the same size or smaller, returning `None` if the value
158
    /// is out of range.
159
    fn checked_truncate<T>(self) -> Option<T>
160
    where
161
        Self: TruncateTarget<T>;
162
}
163
164
impl<T: sealed::Integer> Truncate for T {
165
10.5k
    fn truncate<U>(self) -> U
166
10.5k
    where
167
10.5k
        T: TruncateTarget<U>,
168
    {
169
10.5k
        sealed::TruncateTargetSealed::truncate(self)
170
10.5k
    }
<usize as num_conv::Truncate>::truncate::<u8>
Line
Count
Source
165
5.39k
    fn truncate<U>(self) -> U
166
5.39k
    where
167
5.39k
        T: TruncateTarget<U>,
168
    {
169
5.39k
        sealed::TruncateTargetSealed::truncate(self)
170
5.39k
    }
Unexecuted instantiation: <i32 as num_conv::Truncate>::truncate::<i8>
Unexecuted instantiation: <i32 as num_conv::Truncate>::truncate::<i16>
<u32 as num_conv::Truncate>::truncate::<u8>
Line
Count
Source
165
5.13k
    fn truncate<U>(self) -> U
166
5.13k
    where
167
5.13k
        T: TruncateTarget<U>,
168
    {
169
5.13k
        sealed::TruncateTargetSealed::truncate(self)
170
5.13k
    }
171
172
    fn saturating_truncate<U>(self) -> U
173
    where
174
        T: TruncateTarget<U>,
175
    {
176
        sealed::TruncateTargetSealed::saturating_truncate(self)
177
    }
178
179
    fn checked_truncate<U>(self) -> Option<U>
180
    where
181
        T: TruncateTarget<U>,
182
    {
183
        sealed::TruncateTargetSealed::checked_truncate(self)
184
    }
185
}
186
187
macro_rules! impl_extend {
188
    ($($from:ty => $($to:ty),+;)*) => {$($(
189
        const _: () = assert!(
190
            core::mem::size_of::<$from>() <= core::mem::size_of::<$to>(),
191
            concat!(
192
                "cannot extend ",
193
                stringify!($from),
194
                " to ",
195
                stringify!($to),
196
                " because ",
197
                stringify!($from),
198
                " is larger than ",
199
                stringify!($to)
200
            )
201
        );
202
203
        impl sealed::ExtendTargetSealed<$to> for $from {
204
            #[inline]
205
38.2k
            fn extend(self) -> $to {
206
38.2k
                self as _
207
38.2k
            }
<u8 as num_conv::sealed::ExtendTargetSealed<usize>>::extend
Line
Count
Source
205
10.7k
            fn extend(self) -> $to {
206
10.7k
                self as _
207
10.7k
            }
Unexecuted instantiation: <u8 as num_conv::sealed::ExtendTargetSealed<u16>>::extend
<u8 as num_conv::sealed::ExtendTargetSealed<u32>>::extend
Line
Count
Source
205
7.93k
            fn extend(self) -> $to {
206
7.93k
                self as _
207
7.93k
            }
<i16 as num_conv::sealed::ExtendTargetSealed<i32>>::extend
Line
Count
Source
205
19.5k
            fn extend(self) -> $to {
206
19.5k
                self as _
207
19.5k
            }
Unexecuted instantiation: <u16 as num_conv::sealed::ExtendTargetSealed<u32>>::extend
Unexecuted instantiation: <u16 as num_conv::sealed::ExtendTargetSealed<usize>>::extend
208
        }
209
210
        impl ExtendTarget<$to> for $from {}
211
    )+)*};
212
}
213
214
macro_rules! impl_truncate {
215
    ($($($from:ty),+ => $to:ty;)*) => {$($(
216
        const _: () = assert!(
217
            core::mem::size_of::<$from>() >= core::mem::size_of::<$to>(),
218
            concat!(
219
                "cannot truncate ",
220
                stringify!($from),
221
                " to ",
222
                stringify!($to),
223
                " because ",
224
                stringify!($from),
225
                " is smaller than ",
226
                stringify!($to)
227
            )
228
        );
229
230
        impl sealed::TruncateTargetSealed<$to> for $from {
231
            #[inline]
232
10.5k
            fn truncate(self) -> $to {
233
10.5k
                self as _
234
10.5k
            }
<usize as num_conv::sealed::TruncateTargetSealed<u8>>::truncate
Line
Count
Source
232
5.39k
            fn truncate(self) -> $to {
233
5.39k
                self as _
234
5.39k
            }
Unexecuted instantiation: <i32 as num_conv::sealed::TruncateTargetSealed<i8>>::truncate
Unexecuted instantiation: <i32 as num_conv::sealed::TruncateTargetSealed<i16>>::truncate
<u32 as num_conv::sealed::TruncateTargetSealed<u8>>::truncate
Line
Count
Source
232
5.13k
            fn truncate(self) -> $to {
233
5.13k
                self as _
234
5.13k
            }
235
236
            #[inline]
237
            fn saturating_truncate(self) -> $to {
238
                if self > <$to>::MAX as _ {
239
                    <$to>::MAX
240
                } else if self < <$to>::MIN as _ {
241
                    <$to>::MIN
242
                } else {
243
                    self as _
244
                }
245
            }
246
247
            #[inline]
248
            fn checked_truncate(self) -> Option<$to> {
249
                if self > <$to>::MAX as _ || self < <$to>::MIN as _ {
250
                    None
251
                } else {
252
                    Some(self as _)
253
                }
254
            }
255
        }
256
257
        impl TruncateTarget<$to> for $from {}
258
    )+)*};
259
}
260
261
impl_extend! {
262
    u8 => u8, u16, u32, u64, u128, usize;
263
    u16 => u16, u32, u64, u128, usize;
264
    u32 => u32, u64, u128;
265
    u64 => u64, u128;
266
    u128 => u128;
267
    usize => usize;
268
269
    i8 => i8, i16, i32, i64, i128, isize;
270
    i16 => i16, i32, i64, i128, isize;
271
    i32 => i32, i64, i128;
272
    i64 => i64, i128;
273
    i128 => i128;
274
    isize => isize;
275
}
276
277
impl_truncate! {
278
    u8, u16, u32, u64, u128, usize => u8;
279
    u16, u32, u64, u128, usize => u16;
280
    u32, u64, u128 => u32;
281
    u64, u128 => u64;
282
    u128 => u128;
283
    usize => usize;
284
285
    i8, i16, i32, i64, i128, isize => i8;
286
    i16, i32, i64, i128, isize => i16;
287
    i32, i64, i128 => i32;
288
    i64, i128 => i64;
289
    i128 => i128;
290
    isize => isize;
291
}