Skip to content

Commit a98578f

Browse files
authored
Value: box BigDecimal and Array (#931)
These two types are already internally heap-allocated. And boxing these two would bring down Value to 32 bytes. I hope this is a fair trade off.
1 parent f985330 commit a98578f

File tree

5 files changed

+65
-22
lines changed

5 files changed

+65
-22
lines changed

sea-query-binder/src/sqlx_mysql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl sqlx::IntoArguments<'_, sqlx::mysql::MySql> for SqlxValues {
100100
}
101101
#[cfg(feature = "with-bigdecimal")]
102102
Value::BigDecimal(d) => {
103-
let _ = args.add(d);
103+
let _ = args.add(d.as_deref());
104104
}
105105
#[cfg(feature = "with-json")]
106106
Value::Json(j) => {

sea-query-binder/src/sqlx_postgres.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ impl sqlx::IntoArguments<'_, sqlx::postgres::Postgres> for SqlxValues {
115115
}
116116
#[cfg(feature = "with-bigdecimal")]
117117
Value::BigDecimal(d) => {
118-
let _ = args.add(d);
118+
let _ = args.add(d.as_deref());
119119
}
120120
#[cfg(feature = "with-json")]
121121
Value::Json(j) => {

sea-query-postgres/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ impl ToSql for PostgresValue {
102102
#[cfg(feature = "with-bigdecimal")]
103103
Value::BigDecimal(v) => {
104104
use bigdecimal::ToPrimitive;
105-
v.as_ref()
105+
v.as_deref()
106106
.map(|v| v.to_f64().expect("Fail to convert bigdecimal as f64"))
107107
.to_sql(ty, out)
108108
}

src/value.rs

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,11 @@ pub enum Value {
196196

197197
#[cfg(feature = "with-bigdecimal")]
198198
#[cfg_attr(docsrs, doc(cfg(feature = "with-bigdecimal")))]
199-
BigDecimal(Option<BigDecimal>),
199+
BigDecimal(Option<Box<BigDecimal>>),
200200

201201
#[cfg(feature = "postgres-array")]
202202
#[cfg_attr(docsrs, doc(cfg(feature = "postgres-array")))]
203-
Array(ArrayType, Option<Vec<Value>>),
203+
Array(ArrayType, Option<Box<Vec<Value>>>),
204204

205205
#[cfg(feature = "postgres-vector")]
206206
#[cfg_attr(docsrs, doc(cfg(feature = "postgres-vector")))]
@@ -215,6 +215,19 @@ pub enum Value {
215215
MacAddress(Option<MacAddress>),
216216
}
217217

218+
/// This test is to check if the size of [`Value`] exceeds the limit.
219+
/// If the size exceeds the limit, you should box the variant.
220+
/// Previously, the size was 24. We bumped it to 32 such that `String`
221+
/// can be unboxed.
222+
pub const VALUE_SIZE: usize = check_value_size();
223+
224+
const fn check_value_size() -> usize {
225+
if std::mem::size_of::<Value>() > 32 {
226+
panic!("the size of Value shouldn't be greater than 32 bytes")
227+
}
228+
std::mem::size_of::<Value>()
229+
}
230+
218231
impl std::fmt::Display for Value {
219232
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
220233
write!(f, "{}", CommonSqlQueryBuilder.value_to_string(self))
@@ -543,6 +556,45 @@ macro_rules! type_to_value {
543556
};
544557
}
545558

559+
#[cfg(feature = "with-bigdecimal")]
560+
macro_rules! type_to_box_value {
561+
( $type: ty, $name: ident, $col_type: expr ) => {
562+
impl From<$type> for Value {
563+
fn from(x: $type) -> Value {
564+
Value::$name(Some(Box::new(x)))
565+
}
566+
}
567+
568+
impl Nullable for $type {
569+
fn null() -> Value {
570+
Value::$name(None)
571+
}
572+
}
573+
574+
impl ValueType for $type {
575+
fn try_from(v: Value) -> Result<Self, ValueTypeErr> {
576+
match v {
577+
Value::$name(Some(x)) => Ok(*x),
578+
_ => Err(ValueTypeErr),
579+
}
580+
}
581+
582+
fn type_name() -> String {
583+
stringify!($type).to_owned()
584+
}
585+
586+
fn array_type() -> ArrayType {
587+
ArrayType::$name
588+
}
589+
590+
fn column_type() -> ColumnType {
591+
use ColumnType::*;
592+
$col_type
593+
}
594+
}
595+
};
596+
}
597+
546598
type_to_value!(bool, Bool, Boolean);
547599
type_to_value!(i8, TinyInt, TinyInteger);
548600
type_to_value!(i16, SmallInt, SmallInteger);
@@ -839,7 +891,7 @@ mod with_rust_decimal {
839891
mod with_bigdecimal {
840892
use super::*;
841893

842-
type_to_value!(BigDecimal, BigDecimal, Decimal(None));
894+
type_to_box_value!(BigDecimal, BigDecimal, Decimal(None));
843895
}
844896

845897
#[cfg(feature = "with-uuid")]
@@ -996,7 +1048,7 @@ pub mod with_array {
9961048
fn from(x: Vec<T>) -> Value {
9971049
Value::Array(
9981050
T::array_type(),
999-
Some(x.into_iter().map(|e| e.into()).collect()),
1051+
Some(Box::new(x.into_iter().map(|e| e.into()).collect())),
10001052
)
10011053
}
10021054
}
@@ -1636,12 +1688,14 @@ pub fn sea_value_to_json_value(value: &Value) -> Json {
16361688
#[cfg(feature = "with-bigdecimal")]
16371689
Value::BigDecimal(Some(v)) => {
16381690
use bigdecimal::ToPrimitive;
1639-
v.to_f64().unwrap().into()
1691+
v.as_ref().to_f64().unwrap().into()
16401692
}
16411693
#[cfg(feature = "with-uuid")]
16421694
Value::Uuid(Some(v)) => Json::String(v.to_string()),
16431695
#[cfg(feature = "postgres-array")]
1644-
Value::Array(_, Some(v)) => Json::Array(v.iter().map(sea_value_to_json_value).collect()),
1696+
Value::Array(_, Some(v)) => {
1697+
Json::Array(v.as_ref().iter().map(sea_value_to_json_value).collect())
1698+
}
16451699
#[cfg(feature = "postgres-vector")]
16461700
Value::Vector(Some(v)) => Json::Array(v.as_slice().iter().map(|&v| v.into()).collect()),
16471701
#[cfg(feature = "with-ipnetwork")]
@@ -2409,6 +2463,7 @@ mod hashable_value {
24092463
Value::Int(Some(1)),
24102464
Value::Int(Some(2))
24112465
])
2466+
.into()
24122467
)
24132468
)
24142469
);
@@ -2423,6 +2478,7 @@ mod hashable_value {
24232478
Value::Float(Some(1.0)),
24242479
Value::Float(Some(2.0))
24252480
])
2481+
.into()
24262482
)
24272483
)
24282484
);

tests/size.rs

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)