diff --git a/Cargo.lock b/Cargo.lock index 081fb54cf5b..86205f4e18f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3806,6 +3806,7 @@ dependencies = [ "frunk", "linera-witty", "linera-witty-macros", + "log", "test-case", "thiserror", "tracing", diff --git a/linera-witty/Cargo.toml b/linera-witty/Cargo.toml index 8134d13f6c5..f8bdc9e067f 100644 --- a/linera-witty/Cargo.toml +++ b/linera-witty/Cargo.toml @@ -12,6 +12,7 @@ edition = "2021" [features] default = ["macros"] +log = ["dep:log"] macros = ["linera-witty-macros"] test = ["linera-witty-macros?/test"] wasmer = ["dep:wasmer", "linera-witty-macros?/wasmer", "wasmer-vm"] @@ -22,6 +23,7 @@ anyhow.workspace = true either.workspace = true frunk.workspace = true linera-witty-macros = { workspace = true, optional = true } +log = { workspace = true, optional = true } thiserror.workspace = true wasmer = { workspace = true, optional = true } wasmer-vm = { workspace = true, optional = true } diff --git a/linera-witty/build.rs b/linera-witty/build.rs index 737655a38db..3d2ea4f8b15 100644 --- a/linera-witty/build.rs +++ b/linera-witty/build.rs @@ -3,6 +3,7 @@ fn main() { cfg_aliases::cfg_aliases! { + with_log: { feature = "log" }, with_testing: { any(test, feature = "test") }, with_wasmer: { feature = "wasmer" }, with_wasmtime: { feature = "wasmtime" }, diff --git a/linera-witty/src/type_traits/implementations/log.rs b/linera-witty/src/type_traits/implementations/log.rs new file mode 100644 index 00000000000..e6c21c0b1f7 --- /dev/null +++ b/linera-witty/src/type_traits/implementations/log.rs @@ -0,0 +1,117 @@ +// Copyright (c) Zefchain Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//! Implementations of the custom traits for types from the [`log`] crate. + +use std::borrow::Cow; + +use frunk::{hlist_pat, HList}; +use log::Level; + +use crate::{ + GuestPointer, InstanceWithMemory, Layout, Memory, Runtime, RuntimeError, RuntimeMemory, + WitLoad, WitStore, WitType, +}; + +impl WitType for Level { + const SIZE: u32 = 1; + + type Layout = HList![i8]; + type Dependencies = HList![]; + + fn wit_type_name() -> Cow<'static, str> { + "log-level".into() + } + + fn wit_type_declaration() -> Cow<'static, str> { + concat!( + " enum log-level {\n", + " error,\n", + " warn,\n", + " info,\n", + " debug,\n", + " trace,\n", + " }\n", + ) + .into() + } +} + +impl WitLoad for Level { + fn load( + memory: &Memory<'_, Instance>, + location: GuestPointer, + ) -> Result + where + Instance: InstanceWithMemory, + ::Memory: RuntimeMemory, + { + match u8::load(memory, location)? { + 0 => Ok(Level::Error), + 1 => Ok(Level::Warn), + 2 => Ok(Level::Info), + 3 => Ok(Level::Debug), + 4 => Ok(Level::Trace), + _ => unreachable!("Invalid log level"), + } + } + + fn lift_from( + hlist_pat![discriminant]: ::Flat, + _memory: &Memory<'_, Instance>, + ) -> Result + where + Instance: InstanceWithMemory, + ::Memory: RuntimeMemory, + { + match discriminant { + 0 => Ok(Level::Error), + 1 => Ok(Level::Warn), + 2 => Ok(Level::Info), + 3 => Ok(Level::Debug), + 4 => Ok(Level::Trace), + _ => unreachable!("Invalid log level"), + } + } +} + +impl WitStore for Level { + fn store( + &self, + memory: &mut Memory<'_, Instance>, + location: GuestPointer, + ) -> Result<(), RuntimeError> + where + Instance: InstanceWithMemory, + ::Memory: RuntimeMemory, + { + let discriminant: i8 = match self { + Level::Error => 0, + Level::Warn => 1, + Level::Info => 2, + Level::Debug => 3, + Level::Trace => 4, + }; + + discriminant.store(memory, location) + } + + fn lower( + &self, + memory: &mut Memory<'_, Instance>, + ) -> Result<::Flat, RuntimeError> + where + Instance: InstanceWithMemory, + ::Memory: RuntimeMemory, + { + let discriminant: i8 = match self { + Level::Error => 0, + Level::Warn => 1, + Level::Info => 2, + Level::Debug => 3, + Level::Trace => 4, + }; + + discriminant.lower(memory) + } +} diff --git a/linera-witty/src/type_traits/implementations/mod.rs b/linera-witty/src/type_traits/implementations/mod.rs index bd729252a2c..4e473defc82 100644 --- a/linera-witty/src/type_traits/implementations/mod.rs +++ b/linera-witty/src/type_traits/implementations/mod.rs @@ -5,6 +5,8 @@ mod custom_types; mod frunk; +#[cfg(with_log)] +mod log; mod std; #[cfg(test)] mod tests; diff --git a/linera-witty/src/type_traits/implementations/tests.rs b/linera-witty/src/type_traits/implementations/tests.rs index 404bdf64ada..9c94c78dd3c 100644 --- a/linera-witty/src/type_traits/implementations/tests.rs +++ b/linera-witty/src/type_traits/implementations/tests.rs @@ -202,6 +202,17 @@ fn btree_map() { ); } +/// Test roundtrip of [`log::Level`]. +#[cfg(with_log)] +#[test] +fn log_level() { + use log::Level::*; + for (index, level) in [Error, Warn, Info, Debug, Trace].into_iter().enumerate() { + test_memory_roundtrip(&level, &[index as u8], &[]); + test_flattening_roundtrip(&level, hlist![index as i32], &[]); + } +} + /// Test storing an instance of `T` to memory, checking that the `layout_data` bytes followed by /// the `heap_data` bytes are correctly written, and check that the instance can be loaded from /// those bytes.