diff --git a/src/scripting/mod.rs b/src/scripting/mod.rs index 81527ba..57aeedd 100644 --- a/src/scripting/mod.rs +++ b/src/scripting/mod.rs @@ -1,4 +1,5 @@ pub mod executor; pub mod loader; pub mod record; +pub mod record_serializer; pub mod script; diff --git a/src/scripting/record.rs b/src/scripting/record.rs index c119430..a3afa98 100644 --- a/src/scripting/record.rs +++ b/src/scripting/record.rs @@ -10,6 +10,7 @@ pub enum RecordValue { Int(i64), Float(f64), String(String), + Bytes(Vec), Boolean(bool), Null, Map(Vec<(RecordValue, RecordValue)>), @@ -32,6 +33,7 @@ impl RecordValue { RecordValue::List(l) => { Expr::List(l.into_iter().map(RecordValue::into_expression).collect()) } + RecordValue::Bytes(b) => Expr::Binary(b), } } @@ -69,6 +71,7 @@ impl RecordValue { }; Type::List(Box::new(list_type)) } + RecordValue::Bytes(_) => Type::Binary, } } } @@ -83,6 +86,7 @@ impl ToString for RecordValue { RecordValue::Null => String::new(), RecordValue::Map(_) => String::new(), RecordValue::List(_) => String::new(), + RecordValue::Bytes(_) => String::new(), } } } @@ -145,3 +149,9 @@ impl> From> for RecordValue { Self::List(list) } } + +impl From> for RecordValue { + fn from(b: Vec) -> Self { + Self::Bytes(b) + } +} diff --git a/src/scripting/record_serializer.rs b/src/scripting/record_serializer.rs new file mode 100644 index 0000000..38b10fc --- /dev/null +++ b/src/scripting/record_serializer.rs @@ -0,0 +1,452 @@ +use std::{collections::HashMap, mem}; + +use thiserror::Error; + +use super::record::RecordValue; + +#[derive(Default)] +pub struct RecordSerializer { + list_serializer: Option, + map_serializer: Option, +} +pub struct RecordListSerializer { + serializer: Option>, + entries: Vec, +} +pub struct RecordMapSerializer { + serializer: Option>, + last_key: Option, + entries: Vec<(RecordValue, RecordValue)>, +} + +impl RecordSerializer { + pub fn list_serializer<'a>(&'a mut self, cap: Option) -> &'a mut RecordListSerializer { + if self.list_serializer.is_none() { + self.list_serializer = Some(RecordListSerializer::with_capacity_opt(cap)); + } + self.list_serializer.as_mut().unwrap() + } + + pub fn map_serializer(&mut self, cap: Option) -> &mut RecordMapSerializer { + if self.map_serializer.is_none() { + self.map_serializer = Some(RecordMapSerializer::with_capacity_opt(cap)); + } + self.map_serializer.as_mut().unwrap() + } +} + +impl RecordListSerializer { + pub fn new() -> Self { + Self { + entries: Vec::new(), + serializer: None, + } + } + + pub fn with_capacity(capacity: usize) -> Self { + Self { + entries: Vec::with_capacity(capacity), + serializer: None, + } + } + + pub fn with_capacity_opt(capacity: Option) -> Self { + match capacity { + Some(cap) => Self::with_capacity(cap), + None => Self::new(), + } + } + + pub fn serializer(&mut self) -> &mut RecordSerializer { + if self.serializer.is_none() { + self.serializer = Some(Box::new(RecordSerializer::default())); + } + self.serializer.as_mut().unwrap() + } +} + +impl RecordMapSerializer { + pub fn new() -> Self { + Self { + last_key: None, + entries: Vec::new(), + serializer: None, + } + } + pub fn with_capacity(capacity: usize) -> Self { + Self { + last_key: None, + entries: Vec::with_capacity(capacity), + serializer: None, + } + } + pub fn with_capacity_opt(capacity: Option) -> Self { + match capacity { + Some(cap) => Self::with_capacity(cap), + None => Self::new(), + } + } + pub fn serializer(&mut self) -> &mut RecordSerializer { + if self.serializer.is_none() { + self.serializer = Some(Box::new(RecordSerializer::default())); + } + self.serializer.as_mut().unwrap() + } +} + +#[derive(Error, Debug)] +pub enum RecordSerError { + #[error("{0}")] + Msg(String), + + #[error("Encountered map value before map key")] + ValueBeforeKey, +} + +impl serde::ser::Error for RecordSerError { + fn custom(msg: T) -> Self + where + T: std::fmt::Display, + { + Self::Msg(msg.to_string()) + } +} + +impl<'a> serde::ser::Serializer for &'a mut RecordSerializer { + type Ok = RecordValue; + + type Error = RecordSerError; + + type SerializeSeq = &'a mut RecordListSerializer; + + type SerializeTuple = &'a mut RecordListSerializer; + + type SerializeTupleStruct = &'a mut RecordListSerializer; + + type SerializeTupleVariant = &'a mut RecordListSerializer; + + type SerializeMap = &'a mut RecordMapSerializer; + + type SerializeStruct = &'a mut RecordMapSerializer; + + type SerializeStructVariant = &'a mut RecordMapSerializer; + + fn serialize_bool(self, v: bool) -> Result { + Ok(v.into()) + } + + fn serialize_i8(self, v: i8) -> Result { + Ok((v as i64).into()) + } + + fn serialize_i16(self, v: i16) -> Result { + Ok((v as i64).into()) + } + + fn serialize_i32(self, v: i32) -> Result { + Ok((v as i64).into()) + } + + fn serialize_i64(self, v: i64) -> Result { + Ok(v.into()) + } + + fn serialize_u8(self, v: u8) -> Result { + Ok((v as i64).into()) + } + + fn serialize_u16(self, v: u16) -> Result { + Ok((v as i64).into()) + } + + fn serialize_u32(self, v: u32) -> Result { + Ok((v as i64).into()) + } + + fn serialize_u64(self, v: u64) -> Result { + Ok((v as i64).into()) + } + + fn serialize_f32(self, v: f32) -> Result { + Ok((v as f64).into()) + } + + fn serialize_f64(self, v: f64) -> Result { + Ok(v.into()) + } + + fn serialize_char(self, v: char) -> Result { + Ok(v.to_string().into()) + } + + fn serialize_str(self, v: &str) -> Result { + Ok(v.into()) + } + + fn serialize_bytes(self, v: &[u8]) -> Result { + Ok(v.to_vec().into()) + } + + fn serialize_none(self) -> Result { + Ok(RecordValue::Null) + } + + fn serialize_some(self, value: &T) -> Result + where + T: serde::Serialize, + { + value.serialize(self) + } + + fn serialize_unit(self) -> Result { + self.serialize_none() + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result { + self.serialize_unit() + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result { + self.serialize_str(variant) + } + + fn serialize_newtype_struct( + self, + _name: &'static str, + value: &T, + ) -> Result + where + T: serde::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result + where + T: serde::Serialize, + { + let mut map = HashMap::new(); + map.insert(variant.to_string(), value.serialize(self)?); + Ok(map.into()) + } + + fn serialize_seq(self, len: Option) -> Result { + Ok(self.list_serializer(len)) + } + + fn serialize_tuple(self, len: usize) -> Result { + Ok(self.list_serializer(Some(len))) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + Ok(self.list_serializer(Some(len))) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + len: usize, + ) -> Result { + Ok(self.list_serializer(Some(len))) + } + + fn serialize_map(self, len: Option) -> Result { + Ok(self.map_serializer(len)) + } + + fn serialize_struct( + self, + _name: &'static str, + len: usize, + ) -> Result { + Ok(self.map_serializer(Some(len))) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + len: usize, + ) -> Result { + Ok(self.map_serializer(Some(len))) + } +} + +impl<'a> serde::ser::SerializeTuple for &'a mut RecordListSerializer { + type Ok = RecordValue; + + type Error = RecordSerError; + + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + let val = value.serialize(self.serializer())?; + self.entries.push(val); + + Ok(()) + } + + fn end(self) -> Result { + Ok(mem::take(&mut self.entries).into()) + } +} + +impl<'a> serde::ser::SerializeSeq for &'a mut RecordListSerializer { + type Ok = RecordValue; + + type Error = RecordSerError; + + fn serialize_element(&mut self, value: &T) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + let val = value.serialize(self.serializer())?; + self.entries.push(val); + + Ok(()) + } + + fn end(self) -> Result { + Ok(mem::take(&mut self.entries).into()) + } +} + +impl<'a> serde::ser::SerializeTupleStruct for &'a mut RecordListSerializer { + type Ok = RecordValue; + + type Error = RecordSerError; + + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + let val = value.serialize(self.serializer())?; + self.entries.push(val); + + Ok(()) + } + + fn end(self) -> Result { + Ok(mem::take(&mut self.entries).into()) + } +} + +impl<'a> serde::ser::SerializeTupleVariant for &'a mut RecordListSerializer { + type Ok = RecordValue; + + type Error = RecordSerError; + + fn serialize_field(&mut self, value: &T) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + let val = value.serialize(self.serializer())?; + self.entries.push(val); + + Ok(()) + } + + fn end(self) -> Result { + Ok(mem::take(&mut self.entries).into()) + } +} + +impl<'a> serde::ser::SerializeMap for &'a mut RecordMapSerializer { + type Ok = RecordValue; + + type Error = RecordSerError; + + fn serialize_key(&mut self, key: &T) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + let val = key.serialize(self.serializer())?; + self.last_key = Some(val); + Ok(()) + } + + fn serialize_value(&mut self, value: &T) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + if let Some(last_key) = self.last_key.take() { + let val = value.serialize(self.serializer())?; + self.entries.push((last_key, val)); + + Ok(()) + } else { + Err(RecordSerError::ValueBeforeKey) + } + } + + fn end(self) -> Result { + Ok(RecordValue::Map(mem::take(&mut self.entries))) + } +} + +impl<'a> serde::ser::SerializeStruct for &'a mut RecordMapSerializer { + type Ok = RecordValue; + + type Error = RecordSerError; + + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + let val = value.serialize(self.serializer())?; + self.entries.push((key.into(), val)); + + Ok(()) + } + + fn end(self) -> Result { + Ok(RecordValue::Map(mem::take(&mut self.entries))) + } +} + +impl<'a> serde::ser::SerializeStructVariant for &'a mut RecordMapSerializer { + type Ok = RecordValue; + + type Error = RecordSerError; + + fn serialize_field( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: serde::Serialize, + { + let val = value.serialize(self.serializer())?; + self.entries.push((key.into(), val)); + + Ok(()) + } + + fn end(self) -> Result { + Ok(RecordValue::Map(mem::take(&mut self.entries))) + } +} diff --git a/src/scripting/script.rs b/src/scripting/script.rs index bf3a74e..d0e0383 100644 --- a/src/scripting/script.rs +++ b/src/scripting/script.rs @@ -1,10 +1,13 @@ use std::{marker::PhantomData, path::PathBuf}; +use serde::Serialize; + use crate::error::AppResult; use super::{ executor::{NuExecutor, VarValue}, record::RecordValue, + record_serializer::RecordSerializer, }; /// A trait implemented for a given nu script type to @@ -24,6 +27,17 @@ pub trait ScriptArgs { fn get_args(self) -> Vec; } +impl ScriptArgs for T { + fn get_args(self) -> Vec { + let mut serializer = RecordSerializer::default(); + let val = self.serialize(&mut serializer).unwrap(); + match val { + RecordValue::List(entries) => entries, + val => vec![val], + } + } +} + /// A nu script instance that can be executed pub struct NuScript { path: PathBuf, diff --git a/src/tasks/setup_users.rs b/src/tasks/setup_users.rs index 841dd4a..977e9ef 100644 --- a/src/tasks/setup_users.rs +++ b/src/tasks/setup_users.rs @@ -1,11 +1,6 @@ -use std::collections::HashMap; - use serde::Serialize; -use crate::scripting::{ - record::RecordValue, - script::{Script, ScriptArgs}, -}; +use crate::scripting::script::Script; pub struct SetupUsersScript; @@ -29,22 +24,3 @@ impl Script for SetupUsersScript { "setup-users.nu" } } - -impl ScriptArgs for UsersConfig { - fn get_args(self) -> Vec { - let mut user_cfg_map = HashMap::new(); - let mut user_cfgs = Vec::new(); - - for user in self.users { - let mut user_map: HashMap<&'static str, RecordValue> = HashMap::new(); - user_map.insert("name", user.name.into()); - user_map.insert("password", user.password.into()); - user_map.insert("sudoer", user.sudoer.into()); - user_map.insert("shell", user.shell.into()); - user_cfgs.push(user_map); - } - user_cfg_map.insert("users", user_cfgs); - - vec![user_cfg_map.into()] - } -}