cranpose-core 0.0.60

Core runtime for a Jetpack Compose inspired UI framework in Rust
Documentation
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::slot) enum CheckedU32Delta {
    Add(u32),
    Sub(u32),
}

impl CheckedU32Delta {
    #[inline]
    pub(in crate::slot) fn from_i64(delta: i64, field: &'static str) -> Self {
        if delta >= 0 {
            Self::Add(
                u32::try_from(delta).unwrap_or_else(|_| panic_u32_delta_out_of_range(field, delta)),
            )
        } else {
            Self::Sub(
                u32::try_from(delta.unsigned_abs())
                    .unwrap_or_else(|_| panic_u32_delta_out_of_range(field, delta)),
            )
        }
    }

    #[inline]
    fn as_i64(self) -> i64 {
        match self {
            Self::Add(delta) => i64::from(delta),
            Self::Sub(delta) => -i64::from(delta),
        }
    }
}

#[inline]
pub(crate) fn checked_usize_to_u32(value: usize, field: &'static str) -> u32 {
    u32::try_from(value).unwrap_or_else(|_| panic!("{field} exceeds u32 storage limit: {value}"))
}

#[inline]
pub(in crate::slot) fn checked_usize_to_i64(value: usize, field: &'static str) -> i64 {
    i64::try_from(value)
        .unwrap_or_else(|_| panic!("{field} exceeds i64 mutation delta limit: {value}"))
}

#[inline]
pub(in crate::slot) fn checked_u32_delta(
    value: u32,
    delta: CheckedU32Delta,
    min: u32,
    field: &'static str,
) -> u32 {
    let updated = match delta {
        CheckedU32Delta::Add(delta) => value
            .checked_add(delta)
            .unwrap_or_else(|| panic_u32_delta_overflow(field, value, delta)),
        CheckedU32Delta::Sub(delta) => value
            .checked_sub(delta)
            .unwrap_or_else(|| panic_u32_delta_below_min(field, value, -i64::from(delta), min)),
    };
    if updated < min {
        panic_u32_delta_below_min(field, value, delta.as_i64(), min);
    }
    updated
}

#[cold]
#[inline(never)]
fn panic_u32_delta_out_of_range(field: &'static str, delta: i64) -> ! {
    panic!("{field} delta exceeds u32 storage limit: {delta}");
}

#[cold]
#[inline(never)]
fn panic_u32_delta_overflow(field: &'static str, value: u32, delta: u32) -> ! {
    panic!("{field} mutation overflow: {value} + {delta}");
}

#[cold]
#[inline(never)]
fn panic_u32_delta_below_min(
    field: &'static str,
    value: u32,
    delta: impl Into<i64>,
    min: u32,
) -> ! {
    let delta = delta.into();
    panic!("{field} cannot become smaller than {min}: {value} + {delta}");
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn checked_usize_to_u32_accepts_u32_max() {
        assert_eq!(
            checked_usize_to_u32(u32::MAX as usize, "test field"),
            u32::MAX
        );
    }

    #[test]
    #[should_panic(expected = "test field exceeds u32 storage limit")]
    fn checked_usize_to_u32_rejects_overflow() {
        checked_usize_to_u32(u32::MAX as usize + 1, "test field");
    }

    #[test]
    fn checked_u32_delta_applies_positive_and_negative_deltas() {
        assert_eq!(
            checked_u32_delta(
                10,
                CheckedU32Delta::from_i64(5, "test field"),
                0,
                "test field"
            ),
            15
        );
        assert_eq!(
            checked_u32_delta(
                10,
                CheckedU32Delta::from_i64(-5, "test field"),
                0,
                "test field"
            ),
            5
        );
    }

    #[test]
    #[should_panic(expected = "test field cannot become smaller than 1")]
    fn checked_u32_delta_rejects_values_below_minimum() {
        checked_u32_delta(
            1,
            CheckedU32Delta::from_i64(-1, "test field"),
            1,
            "test field",
        );
    }
}