Learning Rust: feedback on newtype implementation

⚓ Rust    📅 2026-03-18    👤 surdeus    👁️ 1      

surdeus

Hello all,

I have recently started to learn Rust want to understand if I have implemented this zero-cost newtype correctly. You can imagine that Reg represents a register index in a hypothetical emulator. The idea is that when a function takes a Reg, it's guaranteed to hold a valid index, and that we don't have to pay any runtime cost for Reg.

I have done my best to make it fully featured, and to stay idiomatic, but since I'm so new to Rust I would like some feedback on the end result.

Is there something I'm doing wrong here? An improvement I could make? Some things that are overkill? Does it make sense to use #[inline(always)] in all those functions, should it be #[inline], or should I not have the attribute at all?

Thank you very much in advance!

use thiserror::Error;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Reg(usize);

impl Reg {
    pub const MAX_VALUE: usize = 31;

    /// Creates a new `Reg`.
    ///
    /// # Panics
    ///
    /// Will panic if index > MAX_VALUE.
    #[inline(always)]
    pub fn new(index: usize) -> Self {
        Self::try_from(index).expect("register index out of range")
    }

    /// Returns the underlying register index.
    #[inline(always)]
    pub fn as_usize(self) -> usize {
        self.0
    }
}

impl TryFrom<usize> for Reg {
    type Error = RegError;

    #[inline(always)]
    fn try_from(index: usize) -> Result<Self, Self::Error> {
        if index <= Self::MAX_VALUE {
            Ok(Reg(index))
        } else {
            Err(RegError::OutOfRange(index))
        }
    }
}

impl From<Reg> for usize {
    #[inline(always)]
    fn from(reg: Reg) -> Self {
        reg.as_usize()
    }
}

#[derive(Error, Debug, Clone, Copy, PartialEq, Eq)]
pub enum RegError {
    #[error("register index {0} is out of range (max {max})", max = Reg::MAX_VALUE)]
    OutOfRange(usize),
}

8 posts - 6 participants

Read full topic

🏷️ Rust_feed