浏览代码

Added `cast_into` feature for Data

Data can now be cast into higher bit variants when it's lower, and of the same sign.

i.e. i8 can be cast to i16, i32, i64, or i128, but a i32 can't be cast to i8 or i16 as it would overflow.

Just like an i32 can't be cast to u32... though technically it should be able. (This is a TODO)

Also implement some cast_into feature for Bool when dealing with integers. (Another TODO)

Then version bump! 0.1.2!
david 2 月之前
父节点
当前提交
550157111f
共有 3 个文件被更改,包括 204 次插入0 次删除
  1. 3 0
      Cargo.toml
  2. 25 0
      examples/collection_data_example.rs
  3. 176 0
      src/data.rs

+ 3 - 0
Cargo.toml

@@ -3,5 +3,8 @@ name = "shared"
 version = "0.1.1"
 edition = "2021"
 
+[features]
+cast_into = []
+
 [dependencies]
 tokio = { version = "1.40.0", features = ["macros", "rt", "rt-multi-thread", "sync", "time"] }

+ 25 - 0
examples/collection_data_example.rs

@@ -0,0 +1,25 @@
+use shared::Data;
+use std::collections::HashMap;
+
+fn main() {
+    // Let's quickly populate a map
+    let mut map: HashMap<String, Data> = HashMap::from([
+        ("gravity".to_string(), Data::from(9.81_f32)),
+        ("life".to_string(), Data::from(42_i32)),
+        ("cat".to_string(), Data::from("meow".to_string())),
+    ]);
+    // Hmm... ok, looks good.
+    map.insert("direct_insert".to_string(), Data::Bool(true));
+    // Now to stuff it into a single thing...
+    let map: Data = Data::from(map);
+    // Poof! (Now as of v0.1.1 we can't directly insert or get out, as Vec and HashMap have different parameters)
+
+    // Ok let's pull it all back out
+    let m: Result<HashMap<String, Data>, ()> = map.clone().try_into();
+    if let Ok(m) = m {
+        println!("m is {:?}", m);
+    } else {
+        println!("{:?}", map);
+    }
+    // Notice: Even with `cast_into` feature, this type of try_into will fail on any other Data variant (Capt. Obvious: Well yeah, the others are primitives so we could cast them)
+}

+ 176 - 0
src/data.rs

@@ -169,6 +169,7 @@ impl From<HashMap<String, Data>> for Data {
     }
 }
 
+#[cfg(not(feature = "cast_into"))]
 impl TryInto<String> for Data {
     type Error = ();
     fn try_into(self) -> Result<String, Self::Error> {
@@ -179,6 +180,15 @@ impl TryInto<String> for Data {
     }
 }
 
+#[cfg(feature = "cast_into")]
+impl TryInto<String> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<String, Self::Error> {
+        Ok(format!("{}", self)) // Reuse Display trait
+    }
+}
+
+// i8 is the smallest bit variant... so no cast_into feature
 impl TryInto<i8> for Data {
     type Error = ();
     fn try_into(self) -> Result<i8, Self::Error> {
@@ -189,6 +199,7 @@ impl TryInto<i8> for Data {
     }
 }
 
+#[cfg(not(feature = "cast_into"))]
 impl TryInto<i16> for Data {
     type Error = ();
     fn try_into(self) -> Result<i16, Self::Error> {
@@ -199,16 +210,43 @@ impl TryInto<i16> for Data {
     }
 }
 
+#[cfg(feature = "cast_into")]
+impl TryInto<i16> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i16, Self::Error> {
+        match self {
+            Self::I8(v) => Ok(v as i16), // bump up
+            Self::I16(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+#[cfg(not(feature = "cast_into"))]
+impl TryInto<i32> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i32, Self::Error> {
+        match self {
+            Self::I32(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+#[cfg(feature = "cast_into")]
 impl TryInto<i32> for Data {
     type Error = ();
     fn try_into(self) -> Result<i32, Self::Error> {
         match self {
+            Self::I8(v) => Ok(v as i32), // bump up
+            Self::I16(v) => Ok(v as i32), // bump up
             Self::I32(v) => Ok(v),
             _ => Err(()),
         }
     }
 }
 
+#[cfg(not(feature = "cast_into"))]
 impl TryInto<i64> for Data {
     type Error = ();
     fn try_into(self) -> Result<i64, Self::Error> {
@@ -219,6 +257,21 @@ impl TryInto<i64> for Data {
     }
 }
 
+#[cfg(feature = "cast_into")]
+impl TryInto<i64> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i64, Self::Error> {
+        match self {
+            Self::I8(v) => Ok(v as i64), // bump up
+            Self::I16(v) => Ok(v as i64), // bump up
+            Self::I32(v) => Ok(v as i64), // bump up
+            Self::I64(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+#[cfg(not(feature = "cast_into"))]
 impl TryInto<i128> for Data {
     type Error = ();
     fn try_into(self) -> Result<i128, Self::Error> {
@@ -229,6 +282,22 @@ impl TryInto<i128> for Data {
     }
 }
 
+#[cfg(feature = "cast_into")]
+impl TryInto<i128> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i128, Self::Error> {
+        match self {
+            Self::I8(v) => Ok(v as i128), // bump up
+            Self::I16(v) => Ok(v as i128), // bump up
+            Self::I32(v) => Ok(v as i128), // bump up
+            Self::I64(v) => Ok(v as i128), // bump up
+            Self::I128(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+// u8 is the smallest bit variant, so no cast_into
 impl TryInto<u8> for Data {
     type Error = ();
     fn try_into(self) -> Result<u8, Self::Error> {
@@ -239,6 +308,7 @@ impl TryInto<u8> for Data {
     }
 }
 
+#[cfg(not(feature = "cast_into"))]
 impl TryInto<u16> for Data {
     type Error = ();
     fn try_into(self) -> Result<u16, Self::Error> {
@@ -249,6 +319,19 @@ impl TryInto<u16> for Data {
     }
 }
 
+#[cfg(feature = "cast_into")]
+impl TryInto<u16> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u16, Self::Error> {
+        match self {
+            Self::U8(v) => Ok(v as u16), // bump up
+            Self::U16(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+#[cfg(not(feature = "cast_into"))]
 impl TryInto<u32> for Data {
     type Error = ();
     fn try_into(self) -> Result<u32, Self::Error> {
@@ -259,6 +342,20 @@ impl TryInto<u32> for Data {
     }
 }
 
+#[cfg(feature = "cast_into")]
+impl TryInto<u32> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u32, Self::Error> {
+        match self {
+            Self::U8(v) => Ok(v as u32), // bump up
+            Self::U16(v) => Ok(v as u32), // bump up
+            Self::U32(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+#[cfg(not(feature = "cast_into"))]
 impl TryInto<u64> for Data {
     type Error = ();
     fn try_into(self) -> Result<u64, Self::Error> {
@@ -269,16 +366,47 @@ impl TryInto<u64> for Data {
     }
 }
 
+#[cfg(feature = "cast_into")]
+impl TryInto<u64> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u64, Self::Error> {
+        match self {
+            Self::U8(v) => Ok(v as u64), // bump up
+            Self::U16(v) => Ok(v as u64), // bump up
+            Self::U32(v) => Ok(v as u64), // bump up
+            Self::U64(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+#[cfg(not(feature = "cast_into"))]
+impl TryInto<u128> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u128, Self::Error> {
+        match self {
+            Self::U128(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+#[cfg(feature = "cast_into")]
 impl TryInto<u128> for Data {
     type Error = ();
     fn try_into(self) -> Result<u128, Self::Error> {
         match self {
+            Self::U8(v) => Ok(v as u128), // bump up
+            Self::U16(v) => Ok(v as u128), // bump up
+            Self::U32(v) => Ok(v as u128), // bump up
+            Self::U64(v) => Ok(v as u128), // bump up
             Self::U128(v) => Ok(v),
             _ => Err(()),
         }
     }
 }
 
+// because float only has 32 or 64, f32 will have no cast_into
 impl TryInto<f32> for Data {
     type Error = ();
     fn try_into(self) -> Result<f32, Self::Error> {
@@ -289,16 +417,30 @@ impl TryInto<f32> for Data {
     }
 }
 
+#[cfg(not(feature = "cast_into"))]
+impl TryInto<f64> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<f64, Self::Error> {
+        match self {
+            Self::F64(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+#[cfg(feature = "cast_into")]
 impl TryInto<f64> for Data {
     type Error = ();
     fn try_into(self) -> Result<f64, Self::Error> {
         match self {
+            Self::F32(v) => Ok(v as f64), // bump up
             Self::F64(v) => Ok(v),
             _ => Err(()),
         }
     }
 }
 
+// cast_into doesn't make sense here (Todo: Decide if we do want to cast integers based on not equal to zero)
 impl TryInto<bool> for Data {
     type Error = ();
     fn try_into(self) -> Result<bool, Self::Error> {
@@ -309,6 +451,7 @@ impl TryInto<bool> for Data {
     }
 }
 
+// cast_into doesn't make sense here
 impl TryInto<Vec<Data>> for Data {
     type Error = ();
     fn try_into(self) -> Result<Vec<Data>, Self::Error> {
@@ -319,6 +462,7 @@ impl TryInto<Vec<Data>> for Data {
     }
 }
 
+// cast_into doesn't make sense here
 impl TryInto<HashMap<String, Data>> for Data {
     type Error = ();
     fn try_into(self) -> Result<HashMap<String, Data>, Self::Error> {
@@ -329,6 +473,7 @@ impl TryInto<HashMap<String, Data>> for Data {
     }
 }
 
+// To cast Data into Shared<Data>
 impl From<Data> for Shared<Data> {
     fn from(val: Data) -> Self {
         Shared::new(val)
@@ -336,15 +481,23 @@ impl From<Data> for Shared<Data> {
 }
 
 impl Data {
+    /// Is Data not the variant None
+    /// 
+    /// This is useful for using Data similar to a Option
     pub fn is_some(&self) -> bool {
         !matches!(self, Self::None)
     }
+    /// Is Data the variant None
     pub fn is_none(&self) -> bool {
         matches!(self, Self::None)
     }
+    /// Is Data a String
     pub fn is_string(&self) -> bool {
         matches!(self, Self::String(_))
     }
+    /// Is Data a signed/unsigned integer or float
+    /// 
+    /// JSON Number's can hold both a whole number (i.e. signed/unsigned integers) and floats
     pub fn is_number(&self) -> bool {
         match self {
             Self::I8(_) | Self::I16(_) | Self::I32(_) | Self::I64(_) | Self::I128(_) => true,
@@ -353,22 +506,45 @@ impl Data {
             _ => false
         }
     }
+    /// Is Data a signed integer (Regardless of bits)
+    /// 
+    /// i.e. i8, i16, i32, i64, i128 or neither
     pub fn is_int(&self) -> bool {
         match self {
             Self::I8(_) | Self::I16(_) | Self::I32(_) | Self::I64(_) | Self::I128(_) => true,
             _ => false
         }
     }
+    /// Is Data a unsigned integer (Regardless of bits)
+    /// 
+    /// i.e. u8, u16, u32, u64, or u128 or neither
     pub fn is_uint(&self) -> bool {
         match self {
             Self::U8(_) | Self::U16(_) | Self::U32(_) | Self::U64(_) | Self::U128(_) => true,
             _ => false
         }
     }
+    /// Is Data a f32 or f64 or neither
     pub fn is_float(&self) -> bool {
         matches!(self, Self::F32(_) | Self::F64(_))
     }
+    /// Does Data contain something that holds other Data
+    /// 
+    /// Vec<Data> or HashMap<String, Data> are examples of "nested" Data
     pub fn is_nested(&self) -> bool {
         matches!(self, Self::Vec(_) | Self::HashMap(_))
     }
+    /// This will determine the size of signed or unsigned integers and floats
+    /// 
+    /// i.e. i32 is 32, u64 is 64, f32 is 32, u128 is 128 (Meanwhile, anything else is 0, String is 0, Bool is 0, etc.)
+    pub fn bit_variant(&self) -> u8 {
+        match self {
+            Self::I8(_) | Self::U8(_) => 8,
+            Self::I16(_) | Self::U16(_) => 16,
+            Self::I32(_) | Self::U32(_) | Self::F32(_) => 32,
+            Self::I64(_) | Self::U64(_) | Self::F64(_) => 64,
+            Self::I128(_) | Self::U128(_) => 128,
+            _ => 0
+        }
+    }
 }