Skip to content

Commit

Permalink
Add many more number conversions
Browse files Browse the repository at this point in the history
This allows us to write checked conversions from other integer types, including usize.
  • Loading branch information
ObsidianMinor committed Oct 4, 2024
1 parent 90821e3 commit 8906cc3
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 27 deletions.
60 changes: 43 additions & 17 deletions recapn/src/num.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ use core::fmt;
use core::hint::unreachable_unchecked;
use core::num::NonZeroU32;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TryFromIntError(pub(crate) ());

impl fmt::Display for TryFromIntError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("out of range integral type conversion attempted")
}
}

impl core::error::Error for TryFromIntError {}

/// A simple macro to implement cmp traits using the inner type gotten through a get() function
macro_rules! get_cmp {
($ty1:ty, $ty2:ty) => {
Expand Down Expand Up @@ -42,6 +53,33 @@ macro_rules! fwd_fmt_traits {
};
}

macro_rules! from_int_impl {
($dst:ty: $in:ty => $($src:ty),*) => {$(
impl From<$src> for $dst {
#[inline]
fn from(value: $src) -> $dst {
let inner = <$in as From<$src>>::from(value);
<$dst>::new_unwrap(inner)
}
}
)*};
}

macro_rules! try_from_int_impl {
($dst:ty: $in:ty => $($src:ty),*) => {$(
impl TryFrom<$src> for $dst {
type Error = TryFromIntError;

#[inline]
fn try_from(value: $src) -> Result<$dst, TryFromIntError> {
let inner = <$in as TryFrom<$src>>::try_from(value)
.map_err(|_| TryFromIntError(()))?;
<$dst>::new(inner).ok_or(TryFromIntError(()))
}
}
)*};
}

/// A 29 bit integer. It cannot be zero.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct NonZeroU29(NonZeroU32);
Expand Down Expand Up @@ -176,18 +214,15 @@ impl From<Option<NonZeroU29>> for u29 {
}
}

impl From<u16> for u29 {
fn from(v: u16) -> Self {
Self(u32::from(v))
}
}

impl From<u29> for i30 {
fn from(u29(v): u29) -> Self {
Self(v as i32)
}
}

from_int_impl!(u29: u32 => u8, u16);
try_from_int_impl!(u29: u32 => i8, i16, u32, i32, u64, i64, u128, i128, usize, isize);

get_cmp!(NonZeroU29, u29);
get_cmp!(u29, NonZeroU29);

Expand Down Expand Up @@ -242,14 +277,5 @@ impl i30 {

fwd_fmt_traits!(i30);

impl From<u16> for i30 {
fn from(v: u16) -> Self {
Self(i32::from(v))
}
}

impl From<i16> for i30 {
fn from(v: i16) -> Self {
Self(i32::from(v))
}
}
from_int_impl!(i30: i32 => u8, i8, u16, i16);
try_from_int_impl!(i30: i32 => u32, i32, u64, i64, u128, i128, usize, isize);
20 changes: 10 additions & 10 deletions recapn/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1720,7 +1720,7 @@ impl<'a> ObjectReader<'a> {
// The landing pad is another far pointer. The next pointer is a tag describing our
// pointed-to object
// SAFETY: We know from the above that this landing pad is two words, so this is safe
let tag = unsafe { *pad.offset(1.into()).as_ref_unchecked().as_wire_ptr() };
let tag = unsafe { *pad.offset(1u8.into()).as_ref_unchecked().as_wire_ptr() };

let far_ptr = pad_ptr.try_far_ptr()?;
Ok(Content {
Expand Down Expand Up @@ -1838,7 +1838,7 @@ impl<'a> ObjectReader<'a> {
.ok_or(Error::UnsupportedInlineCompositeElementTag)?;

// move past the tag pointer to get the start of the list
let first = unsafe { tag_ptr.offset(1.into()).as_ref_unchecked() };
let first = unsafe { tag_ptr.offset(1u8.into()).as_ref_unchecked() };

let element_count = tag.inline_composite_element_count();

Expand Down Expand Up @@ -3226,7 +3226,7 @@ impl<'a> ObjectBuilder<'a> {
.expect("far pointer cannot point to a read-only segment");

let content = if double_far {
let tag = unsafe { ptr.offset(1.into()).as_ref_unchecked() };
let tag = unsafe { ptr.offset(1u8.into()).as_ref_unchecked() };
let far_ptr = ptr
.as_wire_ptr()
.try_far_ptr()
Expand Down Expand Up @@ -3269,7 +3269,7 @@ impl<'a> ObjectBuilder<'a> {

builder.set_ptr(pad_ptr, WirePtr::NULL);
if far.double_far() {
let content_ptr = unsafe { pad_ptr.offset(1.into()).as_ref_unchecked() };
let content_ptr = unsafe { pad_ptr.offset(1u8.into()).as_ref_unchecked() };
builder.set_ptr(content_ptr, WirePtr::NULL);
}
}
Expand Down Expand Up @@ -3476,7 +3476,7 @@ impl<'a> ObjectBuilder<'a> {
);
// since the list has no size, any pointer is valid here, even one beyond the end of the segment
return Ok((
unsafe { ptr.offset(1.into()).as_ref_unchecked() },
unsafe { ptr.offset(1u8.into()).as_ref_unchecked() },
ObjectLen::ZERO,
self.clone(),
));
Expand Down Expand Up @@ -3637,7 +3637,7 @@ impl<'a> ObjectBuilder<'a> {
.struct_ptr()
.expect("inline composite list with non-struct elements is not supported");

let list_start = unsafe { start.offset(1.into()).as_ref_unchecked() };
let list_start = unsafe { start.offset(1u8.into()).as_ref_unchecked() };
let size = tag.size();

ListContent {
Expand Down Expand Up @@ -5036,7 +5036,7 @@ impl<'a, T: Table> ListBuilder<'a, T> {
builder,
ptr,
table,
element_count: 0.into(),
element_count: ElementCount::ZERO,
element_size,
}
}
Expand Down Expand Up @@ -6697,7 +6697,7 @@ mod tests {
let mut list = builder
.ptr_field_mut(1)
.unwrap()
.init_list(ElementSize::FourBytes, 3.into());
.init_list(ElementSize::FourBytes, 3u8.into());
assert_eq!(list.len().get(), 3);
unsafe {
list.set_data_unchecked::<i32>(0, 200);
Expand All @@ -6709,7 +6709,7 @@ mod tests {
{
let mut list = builder.ptr_field_mut(2).unwrap().init_list(
ElementSize::InlineComposite(StructSize { data: 1, ptrs: 1 }),
4.into(),
4u8.into(),
);
assert_eq!(list.len().get(), 4);
for i in 0..4 {
Expand All @@ -6727,7 +6727,7 @@ mod tests {
let mut list = builder
.ptr_field_mut(3)
.unwrap()
.init_list(ElementSize::Pointer, 5.into());
.init_list(ElementSize::Pointer, 5u8.into());
assert_eq!(list.len().get(), 5);
for i in 0..5 {
let mut element = unsafe {
Expand Down

0 comments on commit 8906cc3

Please sign in to comment.