From f72c4805d9f048f17649a0ab8d6bd3a99421c41b Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 24 Jul 2026 08:22:18 +0000 Subject: [PATCH 1/3] Let Conv<(i32, i32)> for Size check for negative values --- crates/kas-core/Cargo.toml | 2 +- crates/kas-core/src/geom.rs | 48 +++++++++++++++++++---------- crates/kas-soft/src/atlas.rs | 2 +- crates/kas-wgpu/src/draw/atlases.rs | 2 +- 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/crates/kas-core/Cargo.toml b/crates/kas-core/Cargo.toml index c6c41a7f6..0ee94b6b4 100644 --- a/crates/kas-core/Cargo.toml +++ b/crates/kas-core/Cargo.toml @@ -115,7 +115,7 @@ ab_glyph = { version = "0.2.10", optional = true } swash = { version = "0.2.4", features = ["scale"] } linearize = { version = "0.1.5", features = ["derive"] } kas-text = "0.9.0" -easy-cast = "0.6.0" +easy-cast = "0.6.1" pulldown-cmark = { version = "0.13.0", optional = true } [dependencies.kas-macros] diff --git a/crates/kas-core/src/geom.rs b/crates/kas-core/src/geom.rs index cb4b6048d..8d58efd62 100644 --- a/crates/kas-core/src/geom.rs +++ b/crates/kas-core/src/geom.rs @@ -149,23 +149,6 @@ macro_rules! impl_common { self.0 > rhs.0 && self.1 > rhs.1 } } - - impl From<(i32, i32)> for $T { - #[inline] - fn from(v: (i32, i32)) -> Self { - Self(v.0, v.1) - } - } - impl Conv<(i32, i32)> for $T { - #[inline] - fn conv(v: (i32, i32)) -> Self { - Self(v.0, v.1) - } - #[inline] - fn try_conv(v: (i32, i32)) -> Result { - Ok(Self::conv(v)) - } - } }; } @@ -198,6 +181,13 @@ impl Coord { } } +impl From<(i32, i32)> for Coord { + #[inline] + fn from(v: (i32, i32)) -> Self { + Self(v.0, v.1) + } +} + impl std::ops::Sub for Coord { type Output = Offset; @@ -336,6 +326,21 @@ impl Size { } } +impl Conv<(i32, i32)> for Size { + fn try_conv(v: (i32, i32)) -> Result { + if v.0 >= 0 && v.1 >= 0 { + Ok(Size(v.0, v.1)) + } else { + Err(Error::Range) + } + } + + #[inline] + fn conv(v: (i32, i32)) -> Self { + Self::new(v.0, v.1) + } +} + impl std::ops::Add for Size { type Output = Self; @@ -488,6 +493,13 @@ impl Offset { } } +impl From<(i32, i32)> for Offset { + #[inline] + fn from(v: (i32, i32)) -> Self { + Self(v.0, v.1) + } +} + impl std::ops::Neg for Offset { type Output = Self; @@ -567,6 +579,8 @@ impl Conv for kas_text::Vec2 { } } +impl_via_from!((i32, i32): Coord, Offset); + /// An axis-aligned rectangular region /// /// The region is defined by a point `pos` and an extent `size`, allowing easy diff --git a/crates/kas-soft/src/atlas.rs b/crates/kas-soft/src/atlas.rs index 398324a1c..44071e126 100644 --- a/crates/kas-soft/src/atlas.rs +++ b/crates/kas-soft/src/atlas.rs @@ -145,7 +145,7 @@ impl Allocator for Atlases { let origin = (alloc.rectangle.min.x.cast(), alloc.rectangle.min.y.cast()); - let tex_size = Vec2::conv(Size::from(tex_size)); + let tex_size = Vec2::conv(Size::conv(tex_size)); let a = to_vec2(alloc.rectangle.min); let b = to_vec2(alloc.rectangle.max); debug_assert!(Vec2::ZERO <= a && a <= b && b <= tex_size); diff --git a/crates/kas-wgpu/src/draw/atlases.rs b/crates/kas-wgpu/src/draw/atlases.rs index 8c07c353b..399774b3d 100644 --- a/crates/kas-wgpu/src/draw/atlases.rs +++ b/crates/kas-wgpu/src/draw/atlases.rs @@ -272,7 +272,7 @@ impl Allocator for Pipeline { let origin = (alloc.rectangle.min.x.cast(), alloc.rectangle.min.y.cast()); - let tex_size = Vec2::conv(Size::from(tex_size)); + let tex_size = Vec2::conv(Size::conv(tex_size)); let a = to_vec2(alloc.rectangle.min) / tex_size; let b = to_vec2(alloc.rectangle.max) / tex_size; debug_assert!(Vec2::ZERO <= a && a <= b && b <= Vec2::splat(1.0)); From 4c2d7132861c8892b488e90729e268691d7d79af Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 24 Jul 2026 08:30:01 +0000 Subject: [PATCH 2/3] Use easy_cast::impl_via_from! --- crates/kas-core/src/geom/vector.rs | 51 +++--------------------------- 1 file changed, 4 insertions(+), 47 deletions(-) diff --git a/crates/kas-core/src/geom/vector.rs b/crates/kas-core/src/geom/vector.rs index bae4f38a5..b450420b2 100644 --- a/crates/kas-core/src/geom/vector.rs +++ b/crates/kas-core/src/geom/vector.rs @@ -594,16 +594,7 @@ macro_rules! impl_vec2 { $T(arg.0, arg.1) } } - impl Conv<($f, $f)> for $T { - #[inline] - fn conv(arg: ($f, $f)) -> Self { - $T(arg.0, arg.1) - } - #[inline] - fn try_conv(v: ($f, $f)) -> Result { - Ok(Self::conv(v)) - } - } + impl_via_from!(($f, $f): $T); impl From<$T> for ($f, $f) { #[inline] @@ -611,16 +602,7 @@ macro_rules! impl_vec2 { (v.0, v.1) } } - impl Conv<$T> for ($f, $f) { - #[inline] - fn conv(v: $T) -> Self { - (v.0, v.1) - } - #[inline] - fn try_conv(v: $T) -> Result { - Ok(Self::conv(v)) - } - } + impl_via_from!($T: ($f, $f)); impl From> for $T { #[inline] @@ -644,16 +626,7 @@ impl From for Vec2 { Vec2(size.0, size.1) } } -impl Conv for Vec2 { - #[inline] - fn conv(size: kas_text::Vec2) -> Self { - Vec2(size.0, size.1) - } - #[inline] - fn try_conv(v: kas_text::Vec2) -> Result { - Ok(Self::conv(v)) - } -} +impl_via_from!(kas_text::Vec2: Vec2); impl From for kas_text::Vec2 { #[inline] @@ -661,29 +634,13 @@ impl From for kas_text::Vec2 { kas_text::Vec2(size.0, size.1) } } -impl Conv for kas_text::Vec2 { - #[inline] - fn conv(size: Vec2) -> kas_text::Vec2 { - kas_text::Vec2(size.0, size.1) - } - #[inline] - fn try_conv(v: Vec2) -> Result { - Ok(Self::conv(v)) - } -} - impl From for DVec2 { #[inline] fn from(v: Vec2) -> DVec2 { DVec2(v.0.into(), v.1.into()) } } -impl Conv for DVec2 { - #[inline] - fn try_conv(v: Vec2) -> Result { - Ok(DVec2(v.0.into(), v.1.into())) - } -} +impl_via_from!(Vec2: kas_text::Vec2, DVec2); impl ConvApprox for Vec2 { fn try_conv_approx(size: DVec2) -> Result { Ok(Vec2(size.0.try_cast_approx()?, size.1.try_cast_approx()?)) From 22525119ffd6aff0b3cf36431f288c2fc97e874c Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Fri, 24 Jul 2026 10:26:17 +0000 Subject: [PATCH 3/3] Drop implied requirement that Coord is non-negative --- crates/kas-core/src/geom.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/kas-core/src/geom.rs b/crates/kas-core/src/geom.rs index 8d58efd62..da1057de2 100644 --- a/crates/kas-core/src/geom.rs +++ b/crates/kas-core/src/geom.rs @@ -405,12 +405,9 @@ impl std::ops::Div for Size { } /// Convert an [`Offset`] into a [`Coord`] -/// -/// In debug mode this asserts that the result is non-negative. impl Conv for Coord { #[inline] fn try_conv(v: Offset) -> Result { - debug_assert!(v.0 >= 0 && v.1 >= 0, "Coord::conv({v:?}): negative value"); Ok(Self(v.0, v.1)) } }