Selaa lähdekoodia

Expanded shared for Shared and Data

Shared is the same Arc<Mutex<T>> that we know and love...

Data is a enum to store lots of primitive types under one roof.

Together they form Shared<Data> ... Which should allow simplicity, yet being powerful.
david 2 kuukautta sitten
vanhempi
commit
e792ec617c
7 muutettua tiedostoa jossa 510 lisäystä ja 78 poistoa
  1. 1 1
      Cargo.lock
  2. 1 1
      Cargo.toml
  3. 2 0
      README.md
  4. 42 0
      examples/data_example.rs
  5. 375 0
      src/data.rs
  6. 4 76
      src/lib.rs
  7. 85 0
      src/shared.rs

+ 1 - 1
Cargo.lock

@@ -115,7 +115,7 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "shared"
-version = "0.1.0"
+version = "0.1.1"
 dependencies = [
  "tokio",
 ]

+ 1 - 1
Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "shared"
-version = "0.1.0"
+version = "0.1.1"
 edition = "2021"
 
 [dependencies]

+ 2 - 0
README.md

@@ -8,6 +8,8 @@ A Arc Mutex guarded Data.
 
 ```rust
 use shared::Shared;
+
+// Wrap your structure in Shared<S> via Shared::new(S)
 ```
 
 ## Examples

+ 42 - 0
examples/data_example.rs

@@ -0,0 +1,42 @@
+use shared::Data;
+
+// A example borrowing some Data
+fn something(d: &Data) {
+    // Because Data implements Display (It also implements Debug {:?})
+    println!("{}", d);
+}
+
+fn main() {
+    // Let's make a primitive
+    let my_uint: u32 = 42;
+    // Now notice the simplicity of converting from
+    let my_uint: Data = Data::from(my_uint);
+    let my_int: Data = Data::from(1024_i64);
+    let nothing: Data = Data::default(); // Want something empty?
+    
+    // Ok let's call something now
+    something(&my_uint);
+    something(&my_int);
+    something(&nothing);
+
+    // Directly? Sure!
+    println!("uint={} int={}", my_uint, my_int);
+
+    // Let's say we wanted to get it back out (by we know the original type)
+    let uint: Result<u32, ()> = my_uint.clone().try_into();
+    if let Ok(u) = uint {
+        println!("{:?}", u); // Yay, it is a u32
+    } else {
+        println!("{:?}", my_uint); // We had to clone it above so we can print it down here :)
+    }
+    // However, the above would fail if we try_into a different type (even something like u64 or u128 will "fail", despite the underlying being a u32)
+    // Don't want this? Use the `cast_into` feature (Then the u32 or lower will be casted to u64 or u128, but it only works lower bits to higher bits)
+
+    // We can get a general idea of what the type is, even a loose type like JSON's Number (which could be float or integer or even unsigned integer)
+    if my_int.is_number() {
+        println!("{} is a number", my_int);
+    }
+
+    // Data also supports being used in collections such as Vec<Data> and HashMap<String, Data>  (Note: HashMap will require String and Data, if the key is a number it's better to use a Vec)
+    // See collection_data_example.rs
+}

+ 375 - 0
src/data.rs

@@ -0,0 +1,375 @@
+use std::{collections::HashMap, fmt::Display};
+use tokio::select;
+
+use crate::Shared;
+
+#[derive(Debug, PartialEq, Clone)]
+pub enum Data {
+    None,
+    String(String),
+    I8(i8),
+    I16(i16),
+    I32(i32),
+    I64(i64),
+    I128(i128),
+    U8(u8),
+    U16(u16),
+    U32(u32),
+    U64(u64),
+    U128(u128),
+    F32(f32),
+    F64(f64),
+    Bool(bool),
+    Vec(Vec<Data>),
+    HashMap(HashMap<String, Data>),
+}
+
+impl Default for Data {
+    fn default() -> Self {
+        Self::None
+    }
+}
+
+impl Display for Data {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::None => f.write_str("None"),
+            Self::String(s) => f.write_str(&s),
+            Self::I8(i) => f.write_str(format!("{}", i).as_str()),
+            Self::I16(i) => f.write_str(format!("{}", i).as_str()),
+            Self::I32(i) => f.write_str(format!("{}", i).as_str()),
+            Self::I64(i) => f.write_str(format!("{}", i).as_str()),
+            Self::I128(i) => f.write_str(format!("{}", i).as_str()),
+            Self::U8(i) => f.write_str(format!("{}", i).as_str()),
+            Self::U16(i) => f.write_str(format!("{}", i).as_str()),
+            Self::U32(i) => f.write_str(format!("{}", i).as_str()),
+            Self::U64(i) => f.write_str(format!("{}", i).as_str()),
+            Self::U128(i) => f.write_str(format!("{}", i).as_str()),
+            Self::F32(v) => f.write_str(format!("{}", v).as_str()),
+            Self::F64(v) => f.write_str(format!("{}", v).as_str()),
+            Self::Bool(b) => f.write_str(format!("{}", b).as_str()),
+            Self::Vec(v) => {
+                let mut out: String = "[".to_string();
+                for d in v.iter() {
+                    if out != "[" {
+                        out.push_str(", ");
+                    }
+                    out.push_str(format!("{}", d).as_str());
+                }
+                out.push_str("]");
+                f.write_str(out.as_str())
+            },
+            Self::HashMap(hm) => {
+                let mut out: String = "{".to_string();
+                for (k, v) in hm.iter() {
+                    if out != "{" {
+                        out.push_str(", ");
+                    }
+                    out.push_str(format!("{}: {}", k, v).as_str());
+                }
+                out.push_str("}");
+                f.write_str(out.as_str())
+            },
+        }
+    }
+}
+
+impl From<String> for Data {
+    fn from(value: String) -> Self {
+        Self::String(value)
+    }
+}
+
+impl From<i8> for Data {
+    fn from(value: i8) -> Self {
+        Self::I8(value)
+    }
+}
+
+impl From<i16> for Data {
+    fn from(value: i16) -> Self {
+        Self::I16(value)
+    }
+}
+
+impl From<i32> for Data {
+    fn from(value: i32) -> Self {
+        Self::I32(value)
+    }
+}
+
+impl From<i64> for Data {
+    fn from(value: i64) -> Self {
+        Self::I64(value)
+    }
+}
+
+impl From<i128> for Data {
+    fn from(value: i128) -> Self {
+        Self::I128(value)
+    }
+}
+
+impl From<u8> for Data {
+    fn from(value: u8) -> Self {
+        Self::U8(value)
+    }
+}
+
+impl From<u16> for Data {
+    fn from(value: u16) -> Self {
+        Self::U16(value)
+    }
+}
+
+impl From<u32> for Data {
+    fn from(value: u32) -> Self {
+        Self::U32(value)
+    }
+}
+
+impl From<u64> for Data {
+    fn from(value: u64) -> Self {
+        Self::U64(value)
+    }
+}
+
+impl From<u128> for Data {
+    fn from(value: u128) -> Self {
+        Self::U128(value)
+    }
+}
+
+impl From<f32> for Data {
+    fn from(value: f32) -> Self {
+        Self::F32(value)
+    }
+}
+
+impl From<f64> for Data {
+    fn from(value: f64) -> Self {
+        Self::F64(value)
+    }
+}
+
+impl From<bool> for Data {
+    fn from(value: bool) -> Self {
+        Self::Bool(value)
+    }
+}
+
+impl From<Vec<Data>> for Data {
+    fn from(value: Vec<Data>) -> Self {
+        Self::Vec(value)
+    }
+}
+
+impl From<HashMap<String, Data>> for Data {
+    fn from(value: HashMap<String, Data>) -> Self {
+        Self::HashMap(value)
+    }
+}
+
+impl TryInto<String> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<String, Self::Error> {
+        match self {
+            Self::String(s) => Ok(s),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<i8> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i8, Self::Error> {
+        match self {
+            Self::I8(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<i16> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i16, Self::Error> {
+        match self {
+            Self::I16(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<i32> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i32, Self::Error> {
+        match self {
+            Self::I32(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<i64> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i64, Self::Error> {
+        match self {
+            Self::I64(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<i128> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<i128, Self::Error> {
+        match self {
+            Self::I128(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<u8> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u8, Self::Error> {
+        match self {
+            Self::U8(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<u16> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u16, Self::Error> {
+        match self {
+            Self::U16(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<u32> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u32, Self::Error> {
+        match self {
+            Self::U32(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<u64> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u64, Self::Error> {
+        match self {
+            Self::U64(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<u128> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<u128, Self::Error> {
+        match self {
+            Self::U128(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<f32> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<f32, Self::Error> {
+        match self {
+            Self::F32(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<f64> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<f64, Self::Error> {
+        match self {
+            Self::F64(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<bool> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<bool, Self::Error> {
+        match self {
+            Self::Bool(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<Vec<Data>> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<Vec<Data>, Self::Error> {
+        match self {
+            Self::Vec(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl TryInto<HashMap<String, Data>> for Data {
+    type Error = ();
+    fn try_into(self) -> Result<HashMap<String, Data>, Self::Error> {
+        match self {
+            Self::HashMap(v) => Ok(v),
+            _ => Err(()),
+        }
+    }
+}
+
+impl Into<Shared<Data>> for Data {
+    fn into(self) -> Shared<Data> {
+        Shared::new(self)
+    }
+}
+
+impl Data {
+    pub fn is_some(&self) -> bool {
+        !matches!(self, Self::None)
+    }
+    pub fn is_none(&self) -> bool {
+        matches!(self, Self::None)
+    }
+    pub fn is_string(&self) -> bool {
+        matches!(self, Self::String(_))
+    }
+    pub fn is_number(&self) -> bool {
+        match self {
+            Self::I8(_) | Self::I16(_) | Self::I32(_) | Self::I64(_) | Self::I128(_) => true,
+            Self::U8(_) | Self::U16(_) | Self::U32(_) | Self::U64(_) | Self::U128(_) => true,
+            Self::F32(_) | Self::F64(_) => true,
+            _ => false
+        }
+    }
+    pub fn is_int(&self) -> bool {
+        match self {
+            Self::I8(_) | Self::I16(_) | Self::I32(_) | Self::I64(_) | Self::I128(_) => true,
+            _ => false
+        }
+    }
+    pub fn is_uint(&self) -> bool {
+        match self {
+            Self::U8(_) | Self::U16(_) | Self::U32(_) | Self::U64(_) | Self::U128(_) => true,
+            _ => false
+        }
+    }
+    pub fn is_float(&self) -> bool {
+        matches!(self, Self::F32(_) | Self::F64(_))
+    }
+    pub fn is_nested(&self) -> bool {
+        matches!(self, Self::Vec(_) | Self::HashMap(_))
+    }
+}

+ 4 - 76
src/lib.rs

@@ -1,78 +1,6 @@
-use std::sync::Arc;
-use tokio::sync::{Mutex, MutexGuard};
-use tokio::time::{timeout, Duration};
 
-/// Provides a 30 second timeout for lock attempts
-const LOCK_TIMEOUT: u64 = 30;
+mod shared;
+pub use shared::Shared;
 
-#[derive(Clone)]
-pub struct Shared<T> {
-    pub data: Arc<Mutex<T>>,
-}
-
-impl<T> Shared<T> {
-    /// Creates a new Shared of data T
-    ///
-    /// > Want to see a complete example, look at doc_example in the examples directory
-    /// 
-    /// Example:
-    /// ```
-    /// use shared::Shared;
-    ///
-    /// #[derive(Clone)]
-    /// struct Person {
-    ///     pub name: String,
-    ///     pub age: u16
-    /// }
-    ///
-    /// #[tokio::main]
-    /// async fn main() {
-    ///     let shared_data = Shared::new(Person{
-    ///         name: "Test Dummy".to_string(),
-    ///         age: 30
-    ///     });
-    ///
-    ///     // See Shared::lock for using it
-    /// }
-    /// ```
-    pub fn new(data: T) -> Self {
-        Shared {
-            data: Arc::new(Mutex::new(data)),
-        }
-    }
-
-    /// Acquire lock
-    /// 
-    /// > Want to see a complete example, look at doc_example in the examples directory
-    ///
-    /// Using:
-    /// ```
-    /// // See Shared::new for creating a Shared<Person>
-    /// 
-    /// { // Direct access
-    ///     let person = shared_data.lock().await;
-    ///     println!("Person{{name: {}, age: {}}}", person.name, person.age);
-    /// }
-    /// 
-    /// // Using it as a parameter
-    /// async fn get_older(shared: Shared<Person>) {
-    ///     let mut person = shared.lock().await;
-    ///     person.age += 1;
-    /// }
-    /// 
-    /// // Calling
-    /// get_older(shared_data.clone()).await;
-    /// ```
-    pub async fn lock(&self) -> MutexGuard<'_, T> {
-        let result = timeout(Duration::from_secs(LOCK_TIMEOUT), self.data.lock()).await;
-        if let Ok(guard) = result {
-            return guard;
-        }
-        panic!(
-            "Failed to acquire lock in {} seconds.  Deadlock?",
-            LOCK_TIMEOUT
-        );
-
-        // self.data.lock().await
-    }
-}
+mod data;
+pub use data::Data;

+ 85 - 0
src/shared.rs

@@ -0,0 +1,85 @@
+use std::sync::Arc;
+use tokio::sync::{Mutex, MutexGuard};
+use tokio::time::{timeout, Duration};
+
+#[derive(Clone)]
+pub struct Shared<T> {
+    pub data: Arc<Mutex<T>>,
+    pub lock_timeout: u64,
+}
+
+impl<T> Shared<T> {
+    /// Creates a new Shared of data T
+    /// 
+    /// A lock timeout of 30 seconds is assigned by default (Use Shared::with_timeout to set the timeout yourself, or just edit the field as it is public)
+    ///
+    /// > Want to see a complete example, look at doc_example in the examples directory
+    /// 
+    /// Example:
+    /// ```
+    /// use shared::Shared;
+    ///
+    /// #[derive(Clone)]
+    /// struct Person {
+    ///     pub name: String,
+    ///     pub age: u16
+    /// }
+    ///
+    /// #[tokio::main]
+    /// async fn main() {
+    ///     let shared_data = Shared::new(Person{
+    ///         name: "Test Dummy".to_string(),
+    ///         age: 30
+    ///     });
+    ///
+    ///     // See Shared::lock for using it
+    /// }
+    /// ```
+    pub fn new(data: T) -> Self {
+        Shared {
+            data: Arc::new(Mutex::new(data)),
+            lock_timeout: 30_u64,
+        }
+    }
+
+    /// Creates a new Shared of data T with a given timeout in seconds
+    pub fn with_timeout(data: T, timeout: u64) -> Self {
+        Shared { data: Arc::new(Mutex::new(data)), lock_timeout: timeout }
+    }
+
+    /// Acquire lock
+    /// 
+    /// Will wait so many seconds as defined by lock_timeout (This will panic once the timeout is reached)
+    /// 
+    /// > Want to see a complete example, look at doc_example in the examples directory
+    ///
+    /// Using:
+    /// ```
+    /// // See Shared::new for creating a Shared<Person>
+    /// 
+    /// { // Direct access
+    ///     let person = shared_data.lock().await;
+    ///     println!("Person{{name: {}, age: {}}}", person.name, person.age);
+    /// }
+    /// 
+    /// // Using it as a parameter
+    /// async fn get_older(shared: Shared<Person>) {
+    ///     let mut person = shared.lock().await;
+    ///     person.age += 1;
+    /// }
+    /// 
+    /// // Calling
+    /// get_older(shared_data.clone()).await;
+    /// ```
+    pub async fn lock(&self) -> MutexGuard<'_, T> {
+        let result = timeout(Duration::from_secs(self.lock_timeout), self.data.lock()).await;
+        if let Ok(guard) = result {
+            return guard;
+        }
+        panic!(
+            "Failed to acquire lock in {} seconds.  Deadlock?",
+            self.lock_timeout
+        );
+        // self.data.lock().await
+    }
+}