Initial Commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
65
Cargo.lock
generated
Normal file
65
Cargo.lock
generated
Normal file
@@ -0,0 +1,65 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ecc273b49b3205b83d648f0690daa588925572cc5063745bfe547fe7ec8e1a1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "geometry"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
12
Cargo.toml
Normal file
12
Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "geometry"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
bytemuck = { version = "1.22.0", features = ["derive", "extern_crate_alloc"] }
|
||||
|
||||
[lib]
|
||||
name = "geometry_lib"
|
||||
path = "src/lib.rs"
|
||||
2
examples/custom_coord.rs
Normal file
2
examples/custom_coord.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
fn main() {
|
||||
}
|
||||
155
src/basic/basic_coord2d.rs
Normal file
155
src/basic/basic_coord2d.rs
Normal file
@@ -0,0 +1,155 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::{Numeric, SqrtUnit, Widen};
|
||||
|
||||
/// A Simple 2D Coordinate with a AxisUnitag Unit
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Point2D<AxisUnit: Numeric + Copy, U> {
|
||||
pub x: AxisUnit,
|
||||
pub y: AxisUnit,
|
||||
|
||||
#[doc(hidden)]
|
||||
tag: PhantomData<U>
|
||||
}
|
||||
|
||||
/// A representation of some point on a 2D plane.
|
||||
impl<AxisUnit: Numeric + Copy, U> Point2D<AxisUnit, U> {
|
||||
#[inline]
|
||||
pub const fn new(x: AxisUnit, y: AxisUnit) -> Self {
|
||||
Self {
|
||||
x,
|
||||
y,
|
||||
tag: PhantomData
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn min_point(&self, other: &Self) -> Self {
|
||||
let min_x = self.min_x(other);
|
||||
let min_y = self.min_y(other);
|
||||
Self::new(min_x, min_y)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max_point(&self, other: &Self) -> Self {
|
||||
let max_x = self.max_x(other);
|
||||
let max_y = self.max_y(other);
|
||||
Self::new(max_x, max_y)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn min_x(&self, other: &Self) -> AxisUnit {
|
||||
if self.x < other.x { self.x } else { other.x }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn min_y(&self, other: &Self) -> AxisUnit {
|
||||
if self.y < other.y { self.y } else { other.y }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max_x(&self, other: &Self) -> AxisUnit {
|
||||
if self.x > other.x { self.x } else { other.x }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max_y(&self, other: &Self) -> AxisUnit {
|
||||
if self.y > other.y { self.y } else { other.y }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn order_x(&self, other: &Self) -> (AxisUnit, AxisUnit) {
|
||||
if self.x < other.x { (self.x, other.x) } else { (other.x, self.x) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn order_y(&self, other: &Self) -> (AxisUnit, AxisUnit) {
|
||||
if self.y < other.y { (self.y, other.y) } else { (other.y, self.y) }
|
||||
}
|
||||
|
||||
pub fn midpoint(&self, other: &Self) -> Self {
|
||||
// This function could be a lot better if we could specialize, but unfortunately we can't.
|
||||
// As we are (potentially) working with discrete values, we want to avoid the situation
|
||||
// where we are incorrect about the midpoint due to rounding. If we divide both operands by
|
||||
// two, and they both happen to be odd, we'll be incorrect as we'll have rounded down an
|
||||
// extra unit. To circumvent this, we need to do things the long way.
|
||||
//
|
||||
// Consider two points at x unit 3 and 9. The midpoint should be 6. But if we divide first,
|
||||
// we truncate and end up with (3/2 + 9/2) = (1 + 4) = 5. So we have to add first. But if
|
||||
// we add first, there is a chance we could overflow for very large numbers. To avoid this,
|
||||
// we need to offset the numbers by their smallest value, ensuring the addition does not
|
||||
// overflow.
|
||||
let (min_x, max_x) = self.order_x(other);
|
||||
let (min_y, max_y) = self.order_y(other);
|
||||
|
||||
let x = min_x + ((max_x - min_x) / AxisUnit::TWO);
|
||||
let y = min_y + ((max_y - min_y) / AxisUnit::TWO);
|
||||
|
||||
Self::new(x, y)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn distance_x(&self, other: &Self) -> AxisUnit {
|
||||
let (min_x, max_x) = self.order_x(other);
|
||||
max_x - min_x
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn distance_y(&self, other: &Self) -> AxisUnit {
|
||||
let (min_y, max_y) = self.order_y(other);
|
||||
max_y - min_y
|
||||
}
|
||||
}
|
||||
|
||||
impl<AxisUnit: Numeric + Copy + Widen, U> Point2D<AxisUnit, U> {
|
||||
#[inline]
|
||||
pub fn area(&self, other: &Self) -> <AxisUnit as Widen>::Target {
|
||||
let dx = self.distance_x(other);
|
||||
let dy = self.distance_y(other);
|
||||
|
||||
dx.widen() * dy.widen()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn manhattan_distance(&self, other: &Self) -> <AxisUnit as Widen>::Target {
|
||||
self.distance_x(other).widen() + self.distance_y(other).widen()
|
||||
}
|
||||
}
|
||||
|
||||
impl<AxisUnit: Numeric + Copy + Widen<Target: Widen + Copy>, U> Point2D<AxisUnit, U> {
|
||||
fn distance_squared(&self, other: &Self) -> <<AxisUnit as Widen>::Target as Widen>::Target {
|
||||
let dx = self.distance_x(other).widen();
|
||||
let dy = self.distance_y(other).widen();
|
||||
|
||||
let dx2 = (dx*dx).widen();
|
||||
let dy2 = (dy*dy).widen();
|
||||
|
||||
dx2 + dy2
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn dot_product(&self, other: &Self) -> <<AxisUnit as Widen>::Target as Widen>::Target {
|
||||
let square_x = (self.x.widen() * other.x.widen()).widen();
|
||||
let square_y = (self.x.widen() * other.y.widen()).widen();
|
||||
square_x + square_y
|
||||
}
|
||||
}
|
||||
|
||||
impl <AxisUnit: Numeric + Copy + Widen<Target: Widen<Target: SqrtUnit> + Copy>, U> Point2D<AxisUnit, U> {
|
||||
fn distance(&self, other: &Self) -> <<AxisUnit as Widen>::Target as Widen>::Target {
|
||||
let ds = self.distance_squared(other);
|
||||
ds.sqrt_unit()
|
||||
}
|
||||
}
|
||||
|
||||
impl<AxisUnit: Numeric + Copy, U> From<(AxisUnit, AxisUnit)> for Point2D<AxisUnit, U> {
|
||||
fn from(value: (AxisUnit, AxisUnit)) -> Self {
|
||||
Self::new(value.0, value.1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<AxisUnit: Numeric + Copy, U> From<Point2D<AxisUnit, U>> for (AxisUnit, AxisUnit) {
|
||||
fn from(value: Point2D<AxisUnit, U>) -> Self {
|
||||
(value.x, value.y)
|
||||
}
|
||||
}
|
||||
0
src/basic/basic_rect2d.rs
Normal file
0
src/basic/basic_rect2d.rs
Normal file
3
src/basic/mod.rs
Normal file
3
src/basic/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
mod basic_coord2d;
|
||||
|
||||
pub use basic_coord2d::*;
|
||||
11
src/lib.rs
Normal file
11
src/lib.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
#![deny(clippy::all)]
|
||||
#![forbid(unsafe_code)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
mod traits;
|
||||
mod round;
|
||||
pub mod basic;
|
||||
|
||||
pub use round::*;
|
||||
pub use traits::*;
|
||||
9
src/round.rs
Normal file
9
src/round.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
pub enum Round {
|
||||
Floor,
|
||||
Ceiling,
|
||||
|
||||
#[default]
|
||||
Round,
|
||||
}
|
||||
5
src/traits/mod.rs
Normal file
5
src/traits/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
mod numeric;
|
||||
mod primitives;
|
||||
|
||||
pub use numeric::*;
|
||||
pub use primitives::*;
|
||||
86
src/traits/numeric.rs
Normal file
86
src/traits/numeric.rs
Normal file
@@ -0,0 +1,86 @@
|
||||
use std::ops::{Add, Div, Mul, Shl, Shr, Sub};
|
||||
use std::hash::Hash;
|
||||
|
||||
use bytemuck::Zeroable;
|
||||
|
||||
/// Numeric is a partial trait that more generally represents all numeric types supported by the
|
||||
/// engine. This should include both integers and floats, plus any custom types we implement.
|
||||
pub trait Numeric:
|
||||
Add<Self, Output = Self>
|
||||
+ Sub<Self, Output = Self>
|
||||
+ Mul<Self, Output = Self>
|
||||
+ Div<Self, Output = Self>
|
||||
+ PartialEq
|
||||
+ PartialOrd
|
||||
+ Zeroable
|
||||
{
|
||||
const ZERO: Self;
|
||||
const ONE: Self;
|
||||
const TWO: Self;
|
||||
const MAX: Self;
|
||||
const MIN: Self;
|
||||
}
|
||||
|
||||
|
||||
// /// Integer is a trait representing any of the supported engine numeric types.
|
||||
pub trait Integer: Numeric + Shl + Shr + Ord + Eq + Hash {}
|
||||
|
||||
/// Float is a trait representing any of the supported engine floating point types.
|
||||
pub trait Float: Numeric {}
|
||||
|
||||
/// Signed is a trait representing any value supporting both positive and negative values.
|
||||
pub trait Signed: Numeric {}
|
||||
|
||||
/// Unsigned is a trait representing any value that cannot be negative.
|
||||
pub trait Unsigned: Numeric {}
|
||||
|
||||
/// SignedInteger is a convenience trait implemented for all Signed + Integer values
|
||||
pub trait SignedInteger: Integer + Signed {}
|
||||
impl<T: Integer + Signed> SignedInteger for T {}
|
||||
|
||||
/// UnsignedInteger is a convenience trait implemented for all Unsigned + Integer values
|
||||
pub trait UnsignedInteger: Integer + Unsigned {}
|
||||
impl<T: Integer + Unsigned> UnsignedInteger for T {}
|
||||
|
||||
/// UnitSqrt provies a universal sqrt operator for all values which can have their root taken and
|
||||
/// the value represented in the unit itself. For integers, this would be equivalent to isqrt, and
|
||||
/// for floats, the standard sqrt operation.
|
||||
pub trait SqrtUnit {
|
||||
fn sqrt_unit(self) -> Self;
|
||||
}
|
||||
|
||||
pub trait SqrtReal {
|
||||
fn sqrt_real(self) -> f64;
|
||||
}
|
||||
|
||||
|
||||
/// WidenInto guarantees that a type U can be "widened" into some type T such that T:
|
||||
/// 1. Can hold the result of any multiplication of two U values, including T::MAX * T::MAX.
|
||||
/// 2. No data is lost when converting from U to T.
|
||||
///
|
||||
/// In addition, while it isn't guaranteed, preferably any U can be turned into T with little to no
|
||||
/// overhead, such as converting a u16 to u32 with `as`.
|
||||
pub trait WidenInto<T: Numeric>: Numeric {
|
||||
fn widen_into(self) -> T;
|
||||
}
|
||||
|
||||
/// Widen is similar to WidenInto, but only specifies a single associated type to widen into. This
|
||||
/// is useful for code where the context doesn't care what type exactly is widened, only that the
|
||||
/// resulting type is large enough to contain any single math operation on the narrower type.
|
||||
pub trait Widen: Numeric {
|
||||
type Target: Numeric;
|
||||
|
||||
fn widen(self) -> Self::Target;
|
||||
}
|
||||
|
||||
// Ensure WidenInto is also implemented for T => U if the basic Widen trait is implemented.
|
||||
impl<T> WidenInto<<T as Widen>::Target> for T
|
||||
where
|
||||
T: Widen,
|
||||
<T as Widen>::Target: Numeric,
|
||||
{
|
||||
#[inline]
|
||||
fn widen_into(self) -> <Self as Widen>::Target {
|
||||
self.widen()
|
||||
}
|
||||
}
|
||||
191
src/traits/primitives.rs
Normal file
191
src/traits/primitives.rs
Normal file
@@ -0,0 +1,191 @@
|
||||
use private::PrimitiveNumSealed;
|
||||
|
||||
use super::{Float, Integer, Numeric, Signed, SqrtReal, SqrtUnit, Unsigned, Widen, WidenInto};
|
||||
|
||||
mod private {
|
||||
pub trait PrimitiveNumSealed: Copy + Clone {}
|
||||
}
|
||||
|
||||
impl PrimitiveNumSealed for u8 {}
|
||||
impl PrimitiveNumSealed for u16 {}
|
||||
impl PrimitiveNumSealed for u32 {}
|
||||
impl PrimitiveNumSealed for u64 {}
|
||||
impl PrimitiveNumSealed for u128 {}
|
||||
impl PrimitiveNumSealed for usize {}
|
||||
impl PrimitiveNumSealed for i8 {}
|
||||
impl PrimitiveNumSealed for i16 {}
|
||||
impl PrimitiveNumSealed for i32 {}
|
||||
impl PrimitiveNumSealed for i64 {}
|
||||
impl PrimitiveNumSealed for i128 {}
|
||||
impl PrimitiveNumSealed for isize {}
|
||||
impl PrimitiveNumSealed for f32 {}
|
||||
impl PrimitiveNumSealed for f64 {}
|
||||
|
||||
/// A marker trait used to define only primitive Rust number types.
|
||||
pub trait PrimitiveNum: Numeric {}
|
||||
impl<T: PrimitiveNumSealed + Numeric> PrimitiveNum for T {}
|
||||
|
||||
macro_rules! impl_numeric_for_primitive_int {
|
||||
($unit:ty) => {
|
||||
impl Numeric for $unit {
|
||||
const ZERO: Self = 0;
|
||||
const ONE: Self = 1;
|
||||
const TWO: Self = 2;
|
||||
const MAX: Self = <$unit>::MAX;
|
||||
const MIN: Self = <$unit>::MIN;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_numeric_for_primitive_float {
|
||||
($unit:ty) => {
|
||||
impl Numeric for $unit {
|
||||
const ZERO: Self = 0.0;
|
||||
const ONE: Self = 1.0;
|
||||
const TWO: Self = 2.0;
|
||||
const MAX: Self = <$unit>::MAX;
|
||||
const MIN: Self = <$unit>::MIN;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_numeric_for_primitive_int!(u8);
|
||||
impl_numeric_for_primitive_int!(u16);
|
||||
impl_numeric_for_primitive_int!(u32);
|
||||
impl_numeric_for_primitive_int!(u64);
|
||||
impl_numeric_for_primitive_int!(u128);
|
||||
impl_numeric_for_primitive_int!(usize);
|
||||
impl_numeric_for_primitive_int!(i8);
|
||||
impl_numeric_for_primitive_int!(i16);
|
||||
impl_numeric_for_primitive_int!(i32);
|
||||
impl_numeric_for_primitive_int!(i64);
|
||||
impl_numeric_for_primitive_int!(i128);
|
||||
impl_numeric_for_primitive_int!(isize);
|
||||
impl_numeric_for_primitive_float!(f32);
|
||||
impl_numeric_for_primitive_float!(f64);
|
||||
|
||||
impl Integer for u8 {}
|
||||
impl Integer for u16 {}
|
||||
impl Integer for u32 {}
|
||||
impl Integer for u64 {}
|
||||
impl Integer for u128 {}
|
||||
impl Integer for usize {}
|
||||
impl Integer for i8 {}
|
||||
impl Integer for i16 {}
|
||||
impl Integer for i32 {}
|
||||
impl Integer for i64 {}
|
||||
impl Integer for i128 {}
|
||||
impl Integer for isize {}
|
||||
|
||||
impl Float for f32 {}
|
||||
impl Float for f64 {}
|
||||
|
||||
impl Signed for i8 {}
|
||||
impl Signed for i16 {}
|
||||
impl Signed for i32 {}
|
||||
impl Signed for i64 {}
|
||||
impl Signed for i128 {}
|
||||
impl Signed for isize {}
|
||||
impl Signed for f32 {}
|
||||
impl Signed for f64 {}
|
||||
|
||||
impl Unsigned for u8 {}
|
||||
impl Unsigned for u16 {}
|
||||
impl Unsigned for u32 {}
|
||||
impl Unsigned for u64 {}
|
||||
impl Unsigned for u128 {}
|
||||
impl Unsigned for usize {}
|
||||
|
||||
macro_rules! impl_unit_isqrt_unit {
|
||||
($unit:ty) => {
|
||||
impl SqrtUnit for $unit {
|
||||
fn sqrt_unit(self) -> Self {
|
||||
self.isqrt()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_unit_sqrt_unit {
|
||||
($unit:ty) => {
|
||||
impl SqrtUnit for $unit {
|
||||
fn sqrt_unit(self) -> Self {
|
||||
self.sqrt()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_sqrt_real {
|
||||
($unit:ty) => {
|
||||
impl SqrtReal for $unit {
|
||||
fn sqrt_real(self) -> f64 {
|
||||
Into::<f64>::into(self).sqrt()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_unit_isqrt_unit!(u8);
|
||||
impl_unit_isqrt_unit!(u16);
|
||||
impl_unit_isqrt_unit!(u32);
|
||||
impl_unit_isqrt_unit!(u64);
|
||||
impl_unit_isqrt_unit!(u128);
|
||||
impl_unit_isqrt_unit!(usize);
|
||||
impl_unit_isqrt_unit!(i8);
|
||||
impl_unit_isqrt_unit!(i16);
|
||||
impl_unit_isqrt_unit!(i32);
|
||||
impl_unit_isqrt_unit!(i64);
|
||||
impl_unit_isqrt_unit!(i128);
|
||||
impl_unit_isqrt_unit!(isize);
|
||||
impl_unit_sqrt_unit!(f32);
|
||||
impl_unit_sqrt_unit!(f64);
|
||||
|
||||
impl_sqrt_real!(u8);
|
||||
impl_sqrt_real!(u16);
|
||||
impl_sqrt_real!(u32);
|
||||
impl_sqrt_real!(i8);
|
||||
impl_sqrt_real!(i16);
|
||||
impl_sqrt_real!(i32);
|
||||
impl_sqrt_real!(f32);
|
||||
impl_sqrt_real!(f64);
|
||||
|
||||
macro_rules! impl_widen_into {
|
||||
($from:ty => [$($to:ty),+]) => {
|
||||
$(
|
||||
impl WidenInto<$to> for $from { fn widen_into(self) -> $to { self as $to } }
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_widen {
|
||||
($from:ty => $to:ty) => {
|
||||
impl Widen for $from {
|
||||
type Target=$to;
|
||||
|
||||
fn widen(self) -> $to {
|
||||
self as $to
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_widen!(u8 => u16);
|
||||
impl_widen!(u16 => u32);
|
||||
impl_widen!(u32 => u64);
|
||||
impl_widen!(u64 => u128);
|
||||
impl_widen!(i8 => i16);
|
||||
impl_widen!(i16 => i32);
|
||||
impl_widen!(i32 => i64);
|
||||
impl_widen!(i64 => i128);
|
||||
impl_widen!(f32 => f64);
|
||||
|
||||
// Additional widen options for the primitive types
|
||||
impl_widen_into!(u8 => [u32, u64, u128, usize]);
|
||||
impl_widen_into!(u16 => [u64, u128, usize]);
|
||||
impl_widen_into!(u32 => [u128, usize]);
|
||||
impl_widen_into!(u64 => [usize]);
|
||||
impl_widen_into!(i8 => [i32, i64, i128, isize]);
|
||||
impl_widen_into!(i16 => [i64, i128, isize]);
|
||||
impl_widen_into!(i32 => [i128, isize]);
|
||||
impl_widen_into!(i64 => [isize]);
|
||||
Reference in New Issue
Block a user