Selaa lähdekoodia

Add byte-vector optimization to Vec Modelable impl.

Kestrel 2 vuotta sitten
vanhempi
commit
e8b9e93143
2 muutettua tiedostoa jossa 32 lisäystä ja 12 poistoa
  1. 8 2
      microrm/src/model/create.rs
  2. 24 10
      microrm/src/model/modelable.rs

+ 8 - 2
microrm/src/model/create.rs

@@ -135,9 +135,15 @@ mod test {
     }
 
     #[test]
-    #[should_panic]
     fn nonunit_newtype_struct() {
-        super::sql_for_table::<NonUnitNewtype>();
+        assert_eq!(
+            super::sql_for_table::<NonUnitNewtype>(),
+            (
+                r#"DROP TABLE IF EXISTS "non_unit_newtype""#.to_owned(),
+                r#"CREATE TABLE IF NOT EXISTS "non_unit_newtype" (id integer primary key,"newtype" blob)"#
+                    .to_owned()
+            )
+        )
     }
 
     #[derive(serde::Serialize, serde::Deserialize, crate::Entity)]

+ 24 - 10
microrm/src/model/modelable.rs

@@ -138,24 +138,38 @@ impl<'a, T: Modelable> Modelable for &'a T {
     }
 }
 
-impl<T: Modelable + serde::Serialize + serde::de::DeserializeOwned> Modelable for Vec<T> {
+impl<T: Modelable + serde::Serialize + serde::de::DeserializeOwned + 'static> Modelable for Vec<T> {
     fn bind_to(&self, stmt: &mut sqlite::Statement, col: usize) -> sqlite::Result<()> {
+        // We serialize Vec<u8> types directly as a blob
+        if std::mem::size_of::<T>() == 1 && std::any::TypeId::of::<T>() == std::any::TypeId::of::<u8>() {
+            // this bit is unsafe, but is perfectly reasonable...
+            let byte_slice = unsafe { std::slice::from_raw_parts(self.as_ptr() as *const u8, self.len()) };
+            return byte_slice.bind_to(stmt, col)
+        }
         serde_json::to_string(self).unwrap().bind_to(stmt, col)
     }
     fn build_from(stmt: &sqlite::Statement, col_offset: usize) -> sqlite::Result<(Self, usize)>
     where
         Self: Sized,
     {
-        // TODO: add special exception for one-byte datatypes
+        // Deserialize one-byte types directly from the blob
+        if std::mem::size_of::<T>() == 1 && std::any::TypeId::of::<T>() == std::any::TypeId::of::<u8>() {
+            let blob: Vec<u8> = stmt.read(col_offset)?;
 
-        let s = String::build_from(stmt, col_offset)?;
-        Ok((
-            serde_json::from_str::<Vec<T>>(s.0.as_str()).map_err(|e| sqlite::Error {
-                code: None,
-                message: Some(e.to_string()),
-            })?,
-            1,
-        ))
+            // we know the return value is a u8 because the typeid matches, so while normally this
+            // is hilariously unsafe, right now it's perfectly okay.
+            Ok((unsafe { std::mem::transmute::<Vec<u8>, Vec<T>>(blob) }, 1))
+        }
+        else {
+            let s = String::build_from(stmt, col_offset)?;
+            Ok((
+                serde_json::from_str::<Vec<T>>(s.0.as_str()).map_err(|e| sqlite::Error {
+                    code: None,
+                    message: Some(e.to_string()),
+                })?,
+                1,
+            ))
+        }
     }
     fn column_type() -> &'static str where Self: Sized {
         "blob"