Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 72 additions & 5 deletions src/uint/concat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
where
Self: Concat<LIMBS, Output = Uint<WIDE_LIMBS>>,
{
Uint::concat_mixed(self, hi)
self.concat_resize(hi)
}

/// Concatenate the two values, with `self` as least significant and `hi`
Expand All @@ -22,17 +22,55 @@ impl<const LIMBS: usize> Uint<LIMBS> {
where
Self: Concat<HI_LIMBS, Output = Uint<WIDE_LIMBS>>,
{
self.concat_resize(hi)
}

/// Concatenate the two values, with `self` as least significant and `hi`
/// as the most significant. If `WIDE_LIMBS` is not equal to the sum of
/// `LIMBS` and `HI_LIMBS`, then `None` is returned.
#[inline(always)]
#[must_use]
pub const fn concat_checked<const HI_LIMBS: usize, const WIDE_LIMBS: usize>(
&self,
hi: &Uint<HI_LIMBS>,
) -> Option<Uint<WIDE_LIMBS>> {
if LIMBS + HI_LIMBS == WIDE_LIMBS {
Some(self.concat_resize(hi))
} else {
None
}
}

/// Concatenate the two values, with `self` as least significant and `hi`
/// as the most significant. The resulting wide integer may be truncated or
/// extended with zeros depending upon whether its size is less than or greater
/// than the sum of `LIMBS` and `HI_LIMBS`.
#[inline(always)]
#[must_use]
pub const fn concat_resize<const HI_LIMBS: usize, const WIDE_LIMBS: usize>(
&self,
hi: &Uint<HI_LIMBS>,
) -> Uint<WIDE_LIMBS> {
let mut res = Uint::ZERO;
let (res_lo, res_hi) = res.as_mut_uint_ref().split_at_mut(LIMBS);
res_lo.copy_from(self.as_uint_ref());
res_hi.copy_from(hi.as_uint_ref());
let len = if LIMBS + HI_LIMBS <= WIDE_LIMBS {
LIMBS + HI_LIMBS
} else {
WIDE_LIMBS
};
let lo_len = if LIMBS <= len { LIMBS } else { len };
let hi_len = len - lo_len;
let (res_lo, res_hi) = res.as_mut_uint_ref().split_at_mut(lo_len);
res_lo.copy_from(self.as_uint_ref().leading(lo_len));
res_hi
.leading_mut(hi_len)
.copy_from(hi.as_uint_ref().leading(hi_len));
res
}
}

#[cfg(test)]
mod tests {
use crate::{BitOps, U64, U128, U192, Uint};
use crate::{BitOps, U64, U128, U192, U256, Uint};

#[test]
fn concat() {
Expand All @@ -44,6 +82,35 @@ mod tests {
);
}

#[test]
fn concat_checked() {
let hi = U64::from_u64(0x0011223344556677);
let lo = U64::from_u64(0x8899aabbccddeeff);
let Some(wide) = lo.concat_checked(&hi) else {
panic!("invalid concat")
};
assert_eq!(wide, U128::from_u128(0x00112233445566778899aabbccddeeff));

assert!(lo.concat_checked::<{ U64::LIMBS }, 10>(&hi).is_none());
}

#[test]
fn concat_resize_small() {
let hi = U128::from_u64(0x0011223344556677);
let lo = U128::MAX;
assert_eq!(lo.concat_resize(&hi), U64::MAX);
}

#[test]
fn concat_resize_large() {
let hi = U64::from_u64(0x0011223344556677);
let lo = U64::from_u64(0x8899aabbccddeeff);
assert_eq!(
lo.concat_resize(&hi),
U256::from_u128(0x00112233445566778899aabbccddeeff)
);
}

#[test]
fn concat_mixed() {
let hi = U64::from_u64(0x0011223344556677);
Expand Down
63 changes: 59 additions & 4 deletions src/uint/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ impl<const LIMBS: usize> Uint<LIMBS> {
where
Self: SplitEven<Output = Uint<HALF_LIMBS>>,
{
let (src_lo, src_hi) = self.as_uint_ref().split_at(HALF_LIMBS);
(src_lo.to_uint_resize(), src_hi.to_uint_resize())
self.split_resize()
}

/// Split this number into low and high components respectively.
Expand All @@ -20,14 +19,40 @@ impl<const LIMBS: usize> Uint<LIMBS> {
where
Self: Split<LO_LIMBS, Output = Uint<HI_LIMBS>>,
{
let (src_lo, src_hi) = self.as_uint_ref().split_at(LO_LIMBS);
self.split_resize()
}

/// Split this integer into low and high components. If `LIMBS` is not equal to
/// the sum of `LIMBS` and `HI_LIMBS`, then `None` is returned.
#[inline(always)]
#[must_use]
pub const fn split_checked<const LO_LIMBS: usize, const HI_LIMBS: usize>(
&self,
) -> Option<(Uint<LO_LIMBS>, Uint<HI_LIMBS>)> {
if LO_LIMBS + HI_LIMBS == LIMBS {
Some(self.split_resize())
} else {
None
}
}

/// Split this integer into low and high components. The resulting values may be
/// truncated or extended with zeros depending upon whether `LIMBS` is greater or
/// less than the sum of `LO_LIMBS` and `HI_LIMBS`.
#[inline(always)]
#[must_use]
pub const fn split_resize<const LO_LIMBS: usize, const HI_LIMBS: usize>(
&self,
) -> (Uint<LO_LIMBS>, Uint<HI_LIMBS>) {
let lo_len = if LO_LIMBS <= LIMBS { LO_LIMBS } else { LIMBS };
let (src_lo, src_hi) = self.as_uint_ref().split_at(lo_len);
(src_lo.to_uint_resize(), src_hi.to_uint_resize())
}
}

#[cfg(test)]
mod tests {
use crate::{BitOps, U64, U128, U192, Uint};
use crate::{BitOps, U64, U128, U192, U256, Uint};

#[test]
fn split() {
Expand All @@ -36,6 +61,36 @@ mod tests {
assert_eq!(hi, U64::from_u64(0x0011223344556677));
}

#[test]
fn split_checked() {
let Some((lo, hi)) = U128::from_be_hex("00112233445566778899aabbccddeeff").split_checked()
else {
panic!("invalid split")
};
assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff));
assert_eq!(hi, U64::from_u64(0x0011223344556677));

assert!(
U128::from_be_hex("00112233445566778899aabbccddeeff")
.split_checked::<8, 10>()
.is_none()
);
}

#[test]
fn split_resize_small() {
let (lo, hi) = U256::MAX.split_resize();
assert_eq!(lo, U64::MAX);
assert_eq!(hi, U64::MAX);
}

#[test]
fn split_resize_large() {
let (lo, hi) = U128::from_be_hex("00112233445566778899aabbccddeeff").split_resize();
assert_eq!(lo, U64::from_u64(0x8899aabbccddeeff));
assert_eq!(hi, U128::from_u64(0x0011223344556677));
}

#[test]
fn infer_sizes() {
let (lo, hi) = U128::ONE.split();
Expand Down
Loading