Skip to content

Commit

Permalink
Add impls for i128 16-byte integer db conversions
Browse files Browse the repository at this point in the history
rust nightly has i128/u128 as 16-byte integer types, expected to land
into stable at some point in the (near?) future. SQLite's maximum
variable-length integer size is 8-bytes, so this needs to be serialized
into a blob for storage in the database.

Obviously endianness is a concern here; I've opted to use the platform's
native endianness rather than a hard-coded BE/LE choice. This is
contracted out to i128's `from_bytes`/`to_bytes`, which will take care
of the platform-specific endianness for us.

The usage of `unsafe` in the call to i128::from_bytes is to avoid a
potentially expensive extra allocation and looping over the contents of
the vector to copy them to a `[u8; 16]` intermediate. Once [RFC #2000](rust-lang/rfcs#2000) lands in nightly (tracked in [#44580](rust-lang/rust#44580)), [const generics](https://internals.rust-lang.org/t/lang-team-minutes-const-generics/5090) should make it possible to convert the `Vec<u8>` to a fixed-length `[u8; 16]` array in a nicer fashion.
  • Loading branch information
mqudsi committed Sep 5, 2018
1 parent 1f622e6 commit f3f8c68
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ bundled = ["libsqlite3-sys/bundled"]
buildtime_bindgen = ["libsqlite3-sys/buildtime_bindgen"]
limits = []
hooks = []
i128 = []
sqlcipher = ["libsqlite3-sys/sqlcipher"]
unlock_notify = ["libsqlite3-sys/unlock_notify"]
vtab = ["libsqlite3-sys/min_sqlite_version_3_7_7", "lazy_static"]
Expand Down
11 changes: 11 additions & 0 deletions src/types/from_sql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ impl FromSql for Vec<u8> {
}
}

#[cfg(i128)]
impl FromSql for i128 {
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
value.as_blob().map(|b| b.to_vec()).map(|mut v| {
// force the vector to be 16-bytes long for safety reasons
v.resize(16, 0); // ...making the next line actually safe
i128::from_bytes(unsafe { *(&v as &[u8] as *const [u8] as *const [u8; 16]) })
})
}
}

impl<T: FromSql> FromSql for Option<T> {
fn column_result(value: ValueRef) -> FromSqlResult<Self> {
match value {
Expand Down
14 changes: 14 additions & 0 deletions src/types/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ impl From<isize> for Value {
}
}

#[cfg(i128)]
impl From<i128> for Value {
fn from(i: i128) -> Value {
Value::Blob(i.to_bytes().to_vec())
}
}

#[cfg(i128)]
impl From<u128> for Value {
fn from(i: u128) -> Value {
Value::Blob(i.to_bytes().to_vec())
}
}

macro_rules! from_i64(
($t:ty) => (
impl From<$t> for Value {
Expand Down

0 comments on commit f3f8c68

Please sign in to comment.