Skip to content

Commit

Permalink
Added misaligned i128/u128 (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Nov 10, 2022
1 parent fbd96b7 commit 1269981
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 27 deletions.
2 changes: 1 addition & 1 deletion minijinja/src/filters.rs
Expand Up @@ -492,7 +492,7 @@ mod builtins {
pub fn abs(value: Value) -> Result<Value, Error> {
match value.0 {
ValueRepr::I64(x) => Ok(Value::from(x.abs())),
ValueRepr::I128(x) => Ok(Value::from(x.abs())),
ValueRepr::I128(x) => Ok(Value::from(x.0.abs())),
ValueRepr::F64(x) => Ok(Value::from(x.abs())),
_ => Err(Error::new(
ErrorKind::InvalidOperation,
Expand Down
4 changes: 2 additions & 2 deletions minijinja/src/key/mod.rs
Expand Up @@ -82,11 +82,11 @@ impl<'a> Key<'a> {
ValueRepr::U64(v) => TryFrom::try_from(v)
.map(Key::I64)
.map_err(|_| ErrorKind::NonKey.into()),
ValueRepr::U128(v) => TryFrom::try_from(v)
ValueRepr::U128(v) => TryFrom::try_from(v.0)
.map(Key::I64)
.map_err(|_| ErrorKind::NonKey.into()),
ValueRepr::I64(v) => Ok(Key::I64(v)),
ValueRepr::I128(v) => TryFrom::try_from(v)
ValueRepr::I128(v) => TryFrom::try_from(v.0)
.map(Key::I64)
.map_err(|_| ErrorKind::NonKey.into()),
ValueRepr::F64(x) => {
Expand Down
24 changes: 19 additions & 5 deletions minijinja/src/value/argtypes.rs
Expand Up @@ -5,7 +5,9 @@ use std::ops::{Deref, DerefMut};

use crate::error::{Error, ErrorKind};
use crate::key::{Key, StaticKey};
use crate::value::{Arc, MapType, Object, StringType, Value, ValueKind, ValueRepr};
use crate::value::{
Arc, MapType, MisalignedI128, MisalignedU128, Object, StringType, Value, ValueKind, ValueRepr,
};
use crate::vm::State;

/// A utility trait that represents the return value of functions and filters.
Expand Down Expand Up @@ -291,17 +293,29 @@ macro_rules! value_from {
};
}

impl From<i128> for Value {
#[inline(always)]
fn from(val: i128) -> Self {
ValueRepr::I128(MisalignedI128(val)).into()
}
}

impl From<u128> for Value {
#[inline(always)]
fn from(val: u128) -> Self {
ValueRepr::U128(MisalignedU128(val)).into()
}
}

value_from!(bool, Bool);
value_from!(u8, U64);
value_from!(u16, U64);
value_from!(u32, U64);
value_from!(u64, U64);
value_from!(u128, U128);
value_from!(i8, I64);
value_from!(i16, I64);
value_from!(i32, I64);
value_from!(i64, I64);
value_from!(i128, I128);
value_from!(f32, F64);
value_from!(f64, F64);
value_from!(char, Char);
Expand Down Expand Up @@ -351,8 +365,8 @@ macro_rules! primitive_int_try_from {
ValueRepr::U64(val) => val,
// for the intention here see Key::from_borrowed_value
ValueRepr::F64(val) if (val as i64 as f64 == val) => val as i64,
ValueRepr::I128(val) => val,
ValueRepr::U128(val) => val,
ValueRepr::I128(val) => val.0,
ValueRepr::U128(val) => val.0,
});
}
}
Expand Down
36 changes: 24 additions & 12 deletions minijinja/src/value/mod.rs
Expand Up @@ -254,6 +254,18 @@ pub(crate) enum StringType {
Safe,
}

/// An `i128` that intentionally uses packed layout to ensure
/// that `ValueRepr` doesn't blow up in size.
#[derive(Copy, Clone)]
#[repr(packed)]
pub(crate) struct MisalignedI128(pub i128);

/// An `u128` that intentionally uses packed layout to ensure
/// that `ValueRepr` doesn't blow up in size.
#[derive(Copy, Clone)]
#[repr(packed)]
pub(crate) struct MisalignedU128(pub u128);

#[derive(Clone)]
pub(crate) enum ValueRepr {
Undefined,
Expand All @@ -263,8 +275,8 @@ pub(crate) enum ValueRepr {
F64(f64),
Char(char),
None,
U128(u128),
I128(i128),
U128(MisalignedU128),
I128(MisalignedI128),
String(Arc<String>, StringType),
Bytes(Arc<Vec<u8>>),
Seq(Arc<Vec<Value>>),
Expand All @@ -282,8 +294,8 @@ impl fmt::Debug for ValueRepr {
ValueRepr::F64(val) => fmt::Debug::fmt(val, f),
ValueRepr::Char(val) => fmt::Debug::fmt(val, f),
ValueRepr::None => write!(f, "None"),
ValueRepr::U128(val) => fmt::Debug::fmt(val, f),
ValueRepr::I128(val) => fmt::Debug::fmt(val, f),
ValueRepr::U128(val) => fmt::Debug::fmt(&{ val.0 }, f),
ValueRepr::I128(val) => fmt::Debug::fmt(&{ val.0 }, f),
ValueRepr::String(val, _) => fmt::Debug::fmt(val, f),
ValueRepr::Bytes(val) => fmt::Debug::fmt(val, f),
ValueRepr::Seq(val) => fmt::Debug::fmt(val, f),
Expand Down Expand Up @@ -359,7 +371,7 @@ impl fmt::Display for Value {
}
ValueRepr::Char(val) => write!(f, "{}", val),
ValueRepr::None => write!(f, "none"),
ValueRepr::I128(val) => write!(f, "{}", val),
ValueRepr::I128(val) => write!(f, "{}", { val.0 }),
ValueRepr::String(val, _) => write!(f, "{}", val),
ValueRepr::Bytes(val) => write!(f, "{}", String::from_utf8_lossy(val)),
ValueRepr::Seq(values) => {
Expand All @@ -382,7 +394,7 @@ impl fmt::Display for Value {
}
write!(f, "}}")
}
ValueRepr::U128(val) => write!(f, "{}", val),
ValueRepr::U128(val) => write!(f, "{}", { val.0 }),
ValueRepr::Dynamic(x) => write!(f, "{}", x),
}
}
Expand Down Expand Up @@ -523,9 +535,9 @@ impl Value {
match self.0 {
ValueRepr::Bool(val) => val,
ValueRepr::U64(x) => x != 0,
ValueRepr::U128(x) => x != 0,
ValueRepr::U128(x) => x.0 != 0,
ValueRepr::I64(x) => x != 0,
ValueRepr::I128(x) => x != 0,
ValueRepr::I128(x) => x.0 != 0,
ValueRepr::F64(x) => x != 0.0,
ValueRepr::Char(x) => x != '\x00',
ValueRepr::String(ref x, _) => !x.is_empty(),
Expand Down Expand Up @@ -820,11 +832,11 @@ impl Value {
ValueRepr::U64(v) => TryFrom::try_from(v)
.map(Key::I64)
.map_err(|_| ErrorKind::NonKey.into()),
ValueRepr::U128(v) => TryFrom::try_from(v)
ValueRepr::U128(v) => TryFrom::try_from(v.0)
.map(Key::I64)
.map_err(|_| ErrorKind::NonKey.into()),
ValueRepr::I64(v) => Ok(Key::I64(v)),
ValueRepr::I128(v) => TryFrom::try_from(v)
ValueRepr::I128(v) => TryFrom::try_from(v.0)
.map(Key::I64)
.map_err(|_| ErrorKind::NonKey.into()),
ValueRepr::Char(c) => Ok(Key::Char(c)),
Expand Down Expand Up @@ -898,8 +910,8 @@ impl Serialize for Value {
ValueRepr::Char(c) => serializer.serialize_char(c),
ValueRepr::None => serializer.serialize_unit(),
ValueRepr::Undefined => serializer.serialize_unit(),
ValueRepr::U128(u) => serializer.serialize_u128(u),
ValueRepr::I128(i) => serializer.serialize_i128(i),
ValueRepr::U128(u) => serializer.serialize_u128(u.0),
ValueRepr::I128(i) => serializer.serialize_i128(i.0),
ValueRepr::String(ref s, _) => serializer.serialize_str(s),
ValueRepr::Bytes(ref b) => serializer.serialize_bytes(b),
ValueRepr::Seq(ref elements) => elements.serialize(serializer),
Expand Down
8 changes: 4 additions & 4 deletions minijinja/src/value/ops.rs
Expand Up @@ -14,9 +14,9 @@ fn as_f64(value: &Value) -> Option<f64> {
Some(match value.0 {
ValueRepr::Bool(x) => x as i64 as f64,
ValueRepr::U64(x) => x as f64,
ValueRepr::U128(x) => x as f64,
ValueRepr::U128(x) => x.0 as f64,
ValueRepr::I64(x) => x as f64,
ValueRepr::I128(x) => x as f64,
ValueRepr::I128(x) => x.0 as f64,
ValueRepr::F64(x) => x,
_ => return None,
})
Expand All @@ -27,13 +27,13 @@ pub fn coerce(a: &Value, b: &Value) -> Option<CoerceResult> {
// equal mappings are trivial
(ValueRepr::U64(a), ValueRepr::U64(b)) => Some(CoerceResult::I128(*a as i128, *b as i128)),
(ValueRepr::U128(a), ValueRepr::U128(b)) => {
Some(CoerceResult::I128(*a as i128, *b as i128))
Some(CoerceResult::I128(a.0 as i128, b.0 as i128))
}
(ValueRepr::String(a, _), ValueRepr::String(b, _)) => {
Some(CoerceResult::String(a.to_string(), b.to_string()))
}
(ValueRepr::I64(a), ValueRepr::I64(b)) => Some(CoerceResult::I128(*a as i128, *b as i128)),
(ValueRepr::I128(a), ValueRepr::I128(b)) => Some(CoerceResult::I128(*a, *b)),
(ValueRepr::I128(a), ValueRepr::I128(b)) => Some(CoerceResult::I128(a.0, b.0)),
(ValueRepr::F64(a), ValueRepr::F64(b)) => Some(CoerceResult::F64(*a, *b)),

// are floats involved?
Expand Down
7 changes: 4 additions & 3 deletions minijinja/src/value/serialize.rs
Expand Up @@ -5,7 +5,8 @@ use serde::{ser, Serialize, Serializer};
use crate::error::Error;
use crate::key::{Key, KeySerializer, StaticKey};
use crate::value::{
Arc, MapType, StringType, Value, ValueMap, ValueRepr, VALUE_HANDLES, VALUE_HANDLE_MARKER,
Arc, MapType, MisalignedI128, MisalignedU128, StringType, Value, ValueMap, ValueRepr,
VALUE_HANDLES, VALUE_HANDLE_MARKER,
};

pub struct ValueSerializer;
Expand Down Expand Up @@ -43,7 +44,7 @@ impl Serializer for ValueSerializer {
}

fn serialize_i128(self, v: i128) -> Result<Value, Error> {
Ok(ValueRepr::I128(v).into())
Ok(ValueRepr::I128(MisalignedI128(v)).into())
}

fn serialize_u8(self, v: u8) -> Result<Value, Error> {
Expand All @@ -63,7 +64,7 @@ impl Serializer for ValueSerializer {
}

fn serialize_u128(self, v: u128) -> Result<Value, Error> {
Ok(ValueRepr::U128(v).into())
Ok(ValueRepr::U128(MisalignedU128(v)).into())
}

fn serialize_f32(self, v: f32) -> Result<Value, Error> {
Expand Down

0 comments on commit 1269981

Please sign in to comment.