From cb5758e341d4f2811f99fed195d6b7245a96a22b Mon Sep 17 00:00:00 2001 From: Erica Marigold Date: Fri, 13 Oct 2023 00:31:03 -0700 Subject: [PATCH] feat: start work on luau-side exports --- src/lune/builtins/serde/crypto.rs | 150 +++++++++++++++++++++++++++--- src/lune/builtins/serde/mod.rs | 9 ++ src/lune/util/table_builder.rs | 9 ++ 3 files changed, 153 insertions(+), 15 deletions(-) diff --git a/src/lune/builtins/serde/crypto.rs b/src/lune/builtins/serde/crypto.rs index 098ccb2..b177a43 100644 --- a/src/lune/builtins/serde/crypto.rs +++ b/src/lune/builtins/serde/crypto.rs @@ -1,3 +1,6 @@ +use crate::lune::builtins::{ + FromLua, Lua, LuaError, LuaResult, LuaUserData, LuaUserDataMethods, LuaValue, +}; use anyhow::Result; use base64::{engine::general_purpose as Base64, Engine as _}; use ring::digest::{self, digest, Digest as RingDigest}; @@ -105,14 +108,69 @@ impl From for ring::hmac::Algorithm { } } +#[derive(PartialOrd, PartialEq, Ord, Eq)] pub enum EncodingKind { Utf8, Base64, Hex, } +impl From for EncodingKind { + fn from(value: usize) -> Self { + match value { + 0 => Self::Utf8, + 1 => Self::Base64, + 2 => Self::Hex, + _ => panic!("invalid value"), + } + } +} + +impl From for EncodingKind { + fn from(value: i32) -> Self { + Self::from(value as usize) + } +} + +impl From for EncodingKind { + fn from(value: f64) -> Self { + Self::from(value as usize) + } +} + +impl From for EncodingKind { + fn from(value: String) -> Self { + match value.to_lowercase().as_str() { + "utf8" => Self::Utf8, + "base64" => Self::Base64, + "hex" => Self::Hex, + &_ => panic!("invalid value"), + } + } +} + +impl FromLua<'_> for EncodingKind { + fn from_lua(value: LuaValue, _: &Lua) -> LuaResult { + match value { + LuaValue::Integer(int) => Ok(EncodingKind::from(int)), + LuaValue::Number(num) => Ok(EncodingKind::from(num)), + LuaValue::String(str) => Ok(EncodingKind::from(str.to_string_lossy().to_string())), + + _ => Err(LuaError::FromLuaConversionError { + from: value.type_name(), + to: "EncodingKind", + message: Some("value must be a an Integer, Number or String".to_string()), + }), + } + } +} + // Note that compute and digest declared here are identical to those of the below implementation // Quite a bit of boilerplate, is there any way to avoid this without using derive macros? +// impl, C: AsRef<[u8]>> CryptoResult { +// fn update(&mut self, content: String) -> Self {} +// } + impl CryptoResult> { pub fn update(&mut self, content: String) -> Self { self.content = Some(content); @@ -154,7 +212,7 @@ impl CryptoResult { (*self).to_owned() } - pub fn compute(&mut self) -> Self { + fn compute(&mut self) -> Self { let content = match &self.content { Some(inner) => inner.to_owned(), None => "".to_string(), @@ -233,18 +291,80 @@ impl CryptoResult { } } -pub fn test() { - println!( - "{}", - Crypto::sha256::<&str>(None /* or Some("some string!") */) - .update("some string!".to_string()) - .compute() - .digest(EncodingKind::Hex) - .unwrap() - ); - - Crypto::hmac(Some("test"), CryptoAlgo::Sha256) - .compute() - .digest(EncodingKind::Base64) - .unwrap(); +trait HasComputedValue { + fn update(&mut self, value: String) -> Self; + fn compute(&mut self) -> Self; + fn digest(&self, encoding: EncodingKind) -> Result; +} +impl HasComputedValue for CryptoResult> { + fn update(&mut self, content: String) -> Self { + self.update(content) + } + + fn compute(&mut self) -> Self { + self.compute() + } + + fn digest(&self, encoding: EncodingKind) -> Result { + self.digest(encoding) + } +} +impl HasComputedValue for CryptoResult { + fn update(&mut self, content: String) -> Self { + self.update(content) + } + + fn compute(&mut self) -> Self { + self.compute() + } + + fn digest(&self, encoding: EncodingKind) -> Result { + self.digest(encoding) + } +} +impl HasComputedValue for CryptoResult { + fn update(&mut self, content: String) -> Self { + self.update(content) + } + + fn compute(&mut self) -> Self { + self.compute() + } + + fn digest(&self, encoding: EncodingKind) -> Result { + self.digest(encoding) + } +} + +fn register_methods< + 'lua, + C: LuaUserData + HasComputedValue + 'static, + M: LuaUserDataMethods<'lua, C>, +>( + methods: &mut M, +) { + methods.add_method_mut("update", |_, this, value| Ok(this.update(value))); + methods.add_method_mut("compute", |_, this, ()| Ok(this.compute())); + methods.add_method("digest", |_, this, encoding| { + this.digest(encoding) + .map_err(|_| mlua::Error::external("whoopsie!")) + }); +} + +impl LuaUserData for CryptoResult> { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + register_methods(methods); + } +} + +impl LuaUserData for CryptoResult { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + register_methods(methods); + } +} + +impl LuaUserData for CryptoResult { + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + register_methods(methods); + } } diff --git a/src/lune/builtins/serde/mod.rs b/src/lune/builtins/serde/mod.rs index 985ea1d..0acc691 100644 --- a/src/lune/builtins/serde/mod.rs +++ b/src/lune/builtins/serde/mod.rs @@ -5,6 +5,7 @@ pub(super) mod crypto; pub(super) mod encode_decode; use compress_decompress::{compress, decompress, CompressDecompressFormat}; +use crypto::Crypto; use encode_decode::{EncodeDecodeConfig, EncodeDecodeFormat}; use crate::lune::util::TableBuilder; @@ -15,6 +16,14 @@ pub fn create(lua: &'static Lua) -> LuaResult { .with_function("decode", serde_decode)? .with_async_function("compress", serde_compress)? .with_async_function("decompress", serde_decompress)? + .with_table( + "crypto", + TableBuilder::new(lua)? + .with_function("sha1", |_, content: Option| { + Ok(Crypto::sha1(content)) + })? + .build()?, + )? .build_readonly() } diff --git a/src/lune/util/table_builder.rs b/src/lune/util/table_builder.rs index 25ded8e..a64600d 100644 --- a/src/lune/util/table_builder.rs +++ b/src/lune/util/table_builder.rs @@ -66,6 +66,15 @@ impl<'lua> TableBuilder<'lua> { self.with_value(key, LuaValue::Function(f)) } + pub fn with_table(self, key: K, table: LuaTable<'lua>) -> LuaResult + where + K: IntoLua<'lua>, + { + self.tab.raw_set(key, table)?; + + Ok(self) + } + pub fn with_metatable(self, table: LuaTable) -> LuaResult { self.tab.set_metatable(Some(table)); Ok(self)