Skip to content

Commit 7cfcd37

Browse files
authored
Add UintRef (#806)
Adds a reference newtype for a `Limb` slice which can be used as an abstraction for implementing shared functionality for both `Uint` and `BoxedUint`. The initial implementation supports a limited amount of functionality but supports usage as both `&UintRef` and `&mut UintRef`. This includes a common implementation of `fmt` impls shared between `Uint` and `BoxedUint`, replacing a copy-paste implementation. Closes #756
1 parent 51cb9af commit 7cfcd37

File tree

3 files changed

+215
-69
lines changed

3 files changed

+215
-69
lines changed

src/uint.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use zeroize::DefaultIsZeroes;
1313
#[cfg(feature = "extra-sizes")]
1414
pub use extra_sizes::*;
1515

16+
pub use ref_type::UintRef;
17+
1618
use crate::{
1719
Bounded, ConstCtOption, ConstZero, Constants, Encoding, FixedInteger, Int, Integer, Limb,
1820
NonZero, Odd, PrecomputeInverter, PrecomputeInverterWithAdjuster, Word,
@@ -186,6 +188,16 @@ impl<const LIMBS: usize> Uint<LIMBS> {
186188
self.limbs
187189
}
188190

191+
/// Borrow the limbs of this [`Uint`] as a [`UintRef`].
192+
pub const fn as_uint_ref(&self) -> &UintRef {
193+
UintRef::new(&self.limbs)
194+
}
195+
196+
/// Mutably borrow the limbs of this [`Uint`] as a [`UintRef`].
197+
pub const fn as_mut_uint_ref(&mut self) -> &mut UintRef {
198+
UintRef::new_mut(&mut self.limbs)
199+
}
200+
189201
/// Convert to a [`NonZero<Uint<LIMBS>>`].
190202
///
191203
/// Returns some if the original value is non-zero, and false otherwise.
@@ -230,6 +242,18 @@ impl<const LIMBS: usize> AsMut<[Limb]> for Uint<LIMBS> {
230242
}
231243
}
232244

245+
impl<const LIMBS: usize> AsRef<UintRef> for Uint<LIMBS> {
246+
fn as_ref(&self) -> &UintRef {
247+
self.as_uint_ref()
248+
}
249+
}
250+
251+
impl<const LIMBS: usize> AsMut<UintRef> for Uint<LIMBS> {
252+
fn as_mut(&mut self) -> &mut UintRef {
253+
self.as_mut_uint_ref()
254+
}
255+
}
256+
233257
impl<const LIMBS: usize> ConditionallySelectable for Uint<LIMBS> {
234258
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
235259
let mut limbs = [Limb::ZERO; LIMBS];
@@ -313,20 +337,13 @@ impl<const LIMBS: usize> num_traits::One for Uint<LIMBS> {
313337

314338
impl<const LIMBS: usize> fmt::Debug for Uint<LIMBS> {
315339
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
316-
write!(f, "Uint(0x{self:X})")
340+
write!(f, "Uint(0x{:X})", self.as_uint_ref())
317341
}
318342
}
319343

320344
impl<const LIMBS: usize> fmt::Binary for Uint<LIMBS> {
321345
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
322-
if f.alternate() {
323-
write!(f, "0b")?;
324-
}
325-
326-
for limb in self.limbs.iter().rev() {
327-
write!(f, "{:0width$b}", &limb.0, width = Limb::BITS as usize)?;
328-
}
329-
Ok(())
346+
fmt::Binary::fmt(self.as_uint_ref(), f)
330347
}
331348
}
332349

@@ -338,25 +355,13 @@ impl<const LIMBS: usize> fmt::Display for Uint<LIMBS> {
338355

339356
impl<const LIMBS: usize> fmt::LowerHex for Uint<LIMBS> {
340357
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341-
if f.alternate() {
342-
write!(f, "0x")?;
343-
}
344-
for limb in self.limbs.iter().rev() {
345-
write!(f, "{:0width$x}", &limb.0, width = Limb::BYTES * 2)?;
346-
}
347-
Ok(())
358+
fmt::LowerHex::fmt(self.as_uint_ref(), f)
348359
}
349360
}
350361

351362
impl<const LIMBS: usize> fmt::UpperHex for Uint<LIMBS> {
352363
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
353-
if f.alternate() {
354-
write!(f, "0x")?;
355-
}
356-
for limb in self.limbs.iter().rev() {
357-
write!(f, "{:0width$X}", &limb.0, width = Limb::BYTES * 2)?;
358-
}
359-
Ok(())
364+
fmt::UpperHex::fmt(self.as_uint_ref(), f)
360365
}
361366
}
362367

@@ -485,6 +490,7 @@ impl_uint_concat_split_mixed! {
485490

486491
#[cfg(feature = "extra-sizes")]
487492
mod extra_sizes;
493+
mod ref_type;
488494

489495
#[cfg(test)]
490496
#[allow(clippy::unwrap_used)]

src/uint/boxed.rs

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ mod sub_mod;
2828
#[cfg(feature = "rand_core")]
2929
mod rand;
3030

31-
use crate::{Integer, Limb, NonZero, Odd, Word, Zero, modular::BoxedMontyForm};
31+
use crate::{Integer, Limb, NonZero, Odd, UintRef, Word, Zero, modular::BoxedMontyForm};
3232
use alloc::{boxed::Box, vec, vec::Vec};
3333
use core::fmt;
3434
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
@@ -134,20 +134,12 @@ impl BoxedUint {
134134

135135
/// Borrow the inner limbs as a slice of [`Word`]s.
136136
pub fn as_words(&self) -> &[Word] {
137-
// SAFETY: `Limb` is a `repr(transparent)` newtype for `Word`
138-
#[allow(trivial_casts, unsafe_code)]
139-
unsafe {
140-
&*((&*self.limbs as *const [Limb]) as *const [Word])
141-
}
137+
self.as_uint_ref().as_words()
142138
}
143139

144140
/// Borrow the inner limbs as a mutable slice of [`Word`]s.
145141
pub fn as_mut_words(&mut self) -> &mut [Word] {
146-
// SAFETY: `Limb` is a `repr(transparent)` newtype for `Word`
147-
#[allow(trivial_casts, unsafe_code)]
148-
unsafe {
149-
&mut *((&mut *self.limbs as *mut [Limb]) as *mut [Word])
150-
}
142+
self.as_mut_uint_ref().as_mut_words()
151143
}
152144

153145
/// Borrow the inner limbs as a mutable slice of [`Word`]s.
@@ -182,6 +174,16 @@ impl BoxedUint {
182174
self.limbs
183175
}
184176

177+
/// Borrow the limbs of this [`BoxedUint`] as a [`UintRef`].
178+
pub fn as_uint_ref(&self) -> &UintRef {
179+
UintRef::new(&self.limbs)
180+
}
181+
182+
/// Mutably borrow the limbs of this [`BoxedUint`] as a [`UintRef`].
183+
pub fn as_mut_uint_ref(&mut self) -> &mut UintRef {
184+
UintRef::new_mut(&mut self.limbs)
185+
}
186+
185187
/// Get the number of limbs in this [`BoxedUint`].
186188
pub fn nlimbs(&self) -> usize {
187189
self.limbs.len()
@@ -304,6 +306,18 @@ impl AsMut<[Limb]> for BoxedUint {
304306
}
305307
}
306308

309+
impl AsRef<UintRef> for BoxedUint {
310+
fn as_ref(&self) -> &UintRef {
311+
self.as_uint_ref()
312+
}
313+
}
314+
315+
impl AsMut<UintRef> for BoxedUint {
316+
fn as_mut(&mut self) -> &mut UintRef {
317+
self.as_mut_uint_ref()
318+
}
319+
}
320+
307321
impl Default for BoxedUint {
308322
fn default() -> Self {
309323
Self::zero()
@@ -371,7 +385,7 @@ impl Zeroize for BoxedUint {
371385

372386
impl fmt::Debug for BoxedUint {
373387
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
374-
write!(f, "BoxedUint(0x{self:X})")
388+
write!(f, "BoxedUint(0x{:X})", self.as_uint_ref())
375389
}
376390
}
377391

@@ -383,50 +397,19 @@ impl fmt::Display for BoxedUint {
383397

384398
impl fmt::Binary for BoxedUint {
385399
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
386-
if self.limbs.is_empty() {
387-
return fmt::Binary::fmt(&Limb::ZERO, f);
388-
}
389-
390-
if f.alternate() {
391-
write!(f, "0b")?;
392-
}
393-
394-
for limb in self.limbs.iter().rev() {
395-
write!(f, "{:0width$b}", &limb.0, width = Limb::BITS as usize)?;
396-
}
397-
Ok(())
400+
fmt::Binary::fmt(self.as_uint_ref(), f)
398401
}
399402
}
400403

401404
impl fmt::LowerHex for BoxedUint {
402405
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403-
if self.limbs.is_empty() {
404-
return fmt::LowerHex::fmt(&Limb::ZERO, f);
405-
}
406-
407-
if f.alternate() {
408-
write!(f, "0x")?;
409-
}
410-
for limb in self.limbs.iter().rev() {
411-
write!(f, "{:0width$x}", &limb.0, width = Limb::BYTES * 2)?;
412-
}
413-
Ok(())
406+
fmt::LowerHex::fmt(self.as_uint_ref(), f)
414407
}
415408
}
416409

417410
impl fmt::UpperHex for BoxedUint {
418411
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419-
if self.limbs.is_empty() {
420-
return fmt::LowerHex::fmt(&Limb::ZERO, f);
421-
}
422-
423-
if f.alternate() {
424-
write!(f, "0x")?;
425-
}
426-
for limb in self.limbs.iter().rev() {
427-
write!(f, "{:0width$X}", &limb.0, width = Limb::BYTES * 2)?;
428-
}
429-
Ok(())
412+
fmt::UpperHex::fmt(self.as_uint_ref(), f)
430413
}
431414
}
432415

src/uint/ref_type.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
//! Unsigned integer reference type.
2+
3+
use crate::{Limb, Word};
4+
use core::{
5+
fmt,
6+
ops::{Index, IndexMut},
7+
};
8+
9+
/// Unsigned integer reference type.
10+
///
11+
/// This type contains a limb slice which can be borrowed from either a `Uint` or `BoxedUint` and
12+
/// thus provides an abstraction for writing shared implementations.
13+
#[repr(transparent)]
14+
pub struct UintRef(pub [Limb]);
15+
16+
impl UintRef {
17+
/// Create a [`UintRef`] reference type from a [`Limb`] slice.
18+
pub const fn new(limbs: &[Limb]) -> &Self {
19+
// SAFETY: `UintRef` is a `repr(transparent)` newtype for `[Limb]`.
20+
#[allow(trivial_casts, unsafe_code)]
21+
unsafe {
22+
&*(limbs as *const [Limb] as *const UintRef)
23+
}
24+
}
25+
26+
/// Create a mutable [`UintRef`] reference type from a [`Limb`] slice.
27+
pub const fn new_mut(limbs: &mut [Limb]) -> &mut Self {
28+
// SAFETY: `UintRef` is a `repr(transparent)` newtype for `[Limb]`.
29+
#[allow(trivial_casts, unsafe_code)]
30+
unsafe {
31+
&mut *(limbs as *mut [Limb] as *mut UintRef)
32+
}
33+
}
34+
35+
/// Borrow the inner `&[Limb]` slice.
36+
pub const fn as_slice(&self) -> &[Limb] {
37+
&self.0
38+
}
39+
40+
/// Mutably borrow the inner `&mut [Limb]` slice.
41+
pub const fn as_mut_slice(&mut self) -> &mut [Limb] {
42+
&mut self.0
43+
}
44+
45+
/// Borrow the inner limbs as a slice of [`Word`]s.
46+
pub const fn as_words(&self) -> &[Word] {
47+
// SAFETY: `Limb` is a `repr(transparent)` newtype for `Word`
48+
#[allow(trivial_casts, unsafe_code)]
49+
unsafe {
50+
&*((&self.0 as *const [Limb]) as *const [Word])
51+
}
52+
}
53+
54+
/// Borrow the inner limbs as a mutable slice of [`Word`]s.
55+
pub const fn as_mut_words(&mut self) -> &mut [Word] {
56+
// SAFETY: `Limb` is a `repr(transparent)` newtype for `Word`
57+
#[allow(trivial_casts, unsafe_code)]
58+
unsafe {
59+
&mut *((&mut self.0 as *mut [Limb]) as *mut [Word])
60+
}
61+
}
62+
63+
/// Get an iterator over the inner limbs.
64+
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &Limb> {
65+
self.0.iter()
66+
}
67+
68+
/// Get a mutable iterator over the inner limbs.
69+
pub fn iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut Limb> {
70+
self.0.iter_mut()
71+
}
72+
73+
/// Is the inner limb slice empty?
74+
pub fn is_empty(&self) -> bool {
75+
self.0.is_empty()
76+
}
77+
78+
/// Get the number of limbs.
79+
pub fn len(&self) -> usize {
80+
self.0.len()
81+
}
82+
}
83+
84+
impl AsRef<[Limb]> for UintRef {
85+
fn as_ref(&self) -> &[Limb] {
86+
self.as_slice()
87+
}
88+
}
89+
90+
impl AsMut<[Limb]> for UintRef {
91+
fn as_mut(&mut self) -> &mut [Limb] {
92+
self.as_mut_slice()
93+
}
94+
}
95+
96+
impl Index<usize> for UintRef {
97+
type Output = Limb;
98+
99+
fn index(&self, index: usize) -> &Limb {
100+
self.0.index(index)
101+
}
102+
}
103+
104+
impl IndexMut<usize> for UintRef {
105+
fn index_mut(&mut self, index: usize) -> &mut Limb {
106+
self.0.index_mut(index)
107+
}
108+
}
109+
110+
impl fmt::Debug for UintRef {
111+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112+
write!(f, "UintRef(0x{self:X})")
113+
}
114+
}
115+
116+
impl fmt::Binary for UintRef {
117+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
118+
if f.alternate() {
119+
write!(f, "0b")?;
120+
}
121+
122+
for limb in self.iter().rev() {
123+
write!(f, "{:0width$b}", &limb.0, width = Limb::BITS as usize)?;
124+
}
125+
Ok(())
126+
}
127+
}
128+
129+
impl fmt::Display for UintRef {
130+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131+
fmt::UpperHex::fmt(self, f)
132+
}
133+
}
134+
135+
impl fmt::LowerHex for UintRef {
136+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
137+
if f.alternate() {
138+
write!(f, "0x")?;
139+
}
140+
for limb in self.iter().rev() {
141+
write!(f, "{:0width$x}", &limb.0, width = Limb::BYTES * 2)?;
142+
}
143+
Ok(())
144+
}
145+
}
146+
147+
impl fmt::UpperHex for UintRef {
148+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149+
if f.alternate() {
150+
write!(f, "0x")?;
151+
}
152+
for limb in self.iter().rev() {
153+
write!(f, "{:0width$X}", &limb.0, width = Limb::BYTES * 2)?;
154+
}
155+
Ok(())
156+
}
157+
}

0 commit comments

Comments
 (0)