diff --git a/pkl-bind/README.md b/pkl-bind/README.md new file mode 100644 index 0000000..c490721 --- /dev/null +++ b/pkl-bind/README.md @@ -0,0 +1,3 @@ +# Pkl Bind + +Exposing the rust bindings for Apple's [Pkl language](https://pkl-lang.org). diff --git a/pkl-bind/src/evaluator/decoder.rs b/pkl-bind/src/evaluator/decoder.rs index 331364f..6b570ee 100644 --- a/pkl-bind/src/evaluator/decoder.rs +++ b/pkl-bind/src/evaluator/decoder.rs @@ -1,4 +1,3 @@ - /// Derive trait for unmarshalling data from the PKL /// binary format as described /// [here](https://pkl-lang.org/main/current/bindings-specification/binary-encoding.html). @@ -14,6 +13,8 @@ pub trait Pkl { mod tests { use pkl_derive::Pkl; + use crate::log; + use super::*; #[test] @@ -37,6 +38,6 @@ mod tests { let test = Test::unmarshal(data).unwrap(); assert_eq!(test.foo, 1); assert_eq!(test.bar, 2); - println!("Unmarshalled: {:?}", test); + log!(1, "Unmarshalled: {:?}", test); } } diff --git a/pkl-bind/src/evaluator/evaluator.rs b/pkl-bind/src/evaluator/evaluator.rs index f08c35b..6a95012 100644 --- a/pkl-bind/src/evaluator/evaluator.rs +++ b/pkl-bind/src/evaluator/evaluator.rs @@ -1,13 +1,13 @@ -use std::{sync::mpsc::{Sender, Receiver, channel}, any::Any, collections::HashMap, rc::Rc}; +use std::{sync::mpsc::{Sender, channel}, any::Any, collections::HashMap}; use crate::evaluator::msg_api::incoming::IncomingMessage; -use super::{msg_api::{outgoing::{ResourceReader, ModuleReader, Evaluate}, incoming::EvaluateResponse}, module_source::ModuleSource, logger::Logger, evaluator_options::EvaluatorOptions, evaluator_manager::EvaluatorManager}; +use super::{msg_api::{outgoing::{ResourceReader, ModuleReader}, incoming::EvaluateResponse}, + module_source::ModuleSource, evaluator_options::EvaluatorOptions}; // Interface for evaluating pkl modules pub struct Evaluator { // NOTE the lifetime allows us to ignore close() since at the end of the lifetime the Evaluator is killed automatically pub evaluator_id: i64, - pub logger: Logger, // pub manager: Option>, //TODO fix the bidirectional reference pub pending_requests: HashMap>, pub closed: bool, @@ -20,7 +20,6 @@ impl Default for Evaluator { fn default() -> Self { Self { evaluator_id: rand::random(), - logger: Default::default(), // manager: Default::default(), pending_requests: Default::default(), closed: Default::default(), @@ -55,16 +54,16 @@ impl EvaluatorMethods for Evaluator { } fn evaluate_expression_raw(&self, source: &ModuleSource, expr: Option) -> Result { - let request_id: i64 = rand::random::(); - let (send, recv) = channel::(); + // let request_id: i64 = rand::random::(); + // let (send, recv) = channel::(); - let msg = Evaluate { - request_id, - evaluator_id: self.evaluator_id, - module_uri: source.uri().to_string(), - module_text: source.contents().clone(), //FIXME badness - expr, - }; + // let msg = Evaluate { + // request_id, + // evaluator_id: self.evaluator_id, + // module_uri: source.uri().to_string(), + // module_text: source.contents().clone(), //FIXME badness + // expr, + // }; todo!() } diff --git a/pkl-bind/src/evaluator/evaluator_manager.rs b/pkl-bind/src/evaluator/evaluator_manager.rs index 1449947..374bced 100644 --- a/pkl-bind/src/evaluator/evaluator_manager.rs +++ b/pkl-bind/src/evaluator/evaluator_manager.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use crate::evaluator::decoder::Pkl; +use crate::{evaluator::decoder::Pkl, log, plog}; use super::{evaluator::Evaluator, evaluator_options::EvaluatorOptions, msg_api::{incoming::IncomingMessage, outgoing::{OutgoingMessage, CreateEvaluator, CloseEvaluator, Evaluate, ListModulesResponse, PathElement}}}; use super::executor::Executor; @@ -54,7 +54,6 @@ impl EvaluatorManager { let evaluator = Evaluator { evaluator_id: eval_resp.evaluator_id.unwrap(), // if we did not error, then this is guaranteed - logger: Default::default(), // manager: Some(Rc::new(self)), // FIXME see Evaluator.rs pending_requests: Default::default(), closed: false, @@ -97,23 +96,23 @@ impl EvaluatorManager { self.exec.send(OutgoingMessage::CloseEvaluator(close_msg)); //TODO get the data and decode - println!("Data: {:?}", x); + log!(1, "Data: {:?}", x); let data = x.clone().result.expect("failed to get result"); // FIXME fails to decode, need to unmarshal data - print!("Data: "); + log!(1, "Data: "); for d in &data { - print!("{:#04X}, ", d); + plog!(1, "{:#04X}, ", d); } - println!(); + log!(1, ""); let res = T::unmarshal(data); - println!("Res: {:?}", res); + log!(1, "Res: {:?}", res); return res; }, - IncomingMessage::ReadResource(x) => todo!(), - IncomingMessage::ReadModule(x) => todo!(), - IncomingMessage::ListResources(x) => todo!(), + IncomingMessage::ReadResource(_x) => todo!(), + IncomingMessage::ReadModule(_x) => todo!(), + IncomingMessage::ListResources(_x) => todo!(), IncomingMessage::ListModules(x) => { // get all the files in the module: let path = PathBuf::from(file.clone()); @@ -122,7 +121,7 @@ impl EvaluatorManager { // files = std::fs::read_dir(path); // TODO } - let mut modules: Vec = vec![]; + let /*mut*/ modules: Vec = vec![]; // for file in files { // // TODO make module // } @@ -134,7 +133,7 @@ impl EvaluatorManager { error: None, }; - let resp = self.exec.senrec(OutgoingMessage::ListModulesResponse(list_resp)).expect("Failed to send/receive data"); + let _resp = self.exec.senrec(OutgoingMessage::ListModulesResponse(list_resp)).expect("Failed to send/receive data"); }, IncomingMessage::Log(_) => todo!(), @@ -146,10 +145,6 @@ impl EvaluatorManager { // send any read_module_response // send the close evaluator } - - pub fn create_evaluator(&self, none: Option<()>) -> i64 { - todo!() - } } impl Drop for EvaluatorManager { @@ -170,7 +165,7 @@ impl Drop for EvaluatorManager { #[cfg(test)] mod tests { use pkl_derive::Pkl; - use crate::evaluator::decoder::Pkl; + use crate::evaluator::{decoder::Pkl, module_source::file_source}; use super::*; @@ -194,8 +189,7 @@ mod tests { let evaluator = eval.new_evaluator(None).expect("Failed to create a new evaluator"); - //TODO remove my paths - let test: Test = eval.evaluate_module::("file:///home/stormblessed/Code/pkl-rust/pkl-bind/src/evaluator/tests/test.pkl".into(), evaluator).expect("Failed to obtain result"); + let test: Test = eval.evaluate_module::(file_source("src/evaluator/tests/test.pkl".into()).uri().to_string(), evaluator).expect("Failed to obtain result"); assert_eq!(test.foo, 1); assert_eq!(test.bar, 2); diff --git a/pkl-bind/src/evaluator/evaluator_options.rs b/pkl-bind/src/evaluator/evaluator_options.rs index a41ff40..3d4264d 100644 --- a/pkl-bind/src/evaluator/evaluator_options.rs +++ b/pkl-bind/src/evaluator/evaluator_options.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, path::PathBuf}; use dirs::home_dir; use std::env; -use super::{msg_api::outgoing::{ResourceReader, ModuleReader}, logger::Logger}; +use super::msg_api::outgoing::{ResourceReader, ModuleReader}; //TODO documentation //TODO this should be taken from a pkl file in the future @@ -10,7 +10,6 @@ pub struct EvaluatorOptions { pub properties: HashMap, pub env: HashMap, pub module_paths: Vec, - pub logger: Logger, pub output_format: String, pub allowed_modules: Vec, pub allowed_resources: Vec, @@ -19,7 +18,7 @@ pub struct EvaluatorOptions { pub cache_dir: PathBuf, pub root_dir: String, //TODO this should also be a path pub project_dir: String, //TODO this should be a path - pub declared_project_dependency: ProjectDependencies + pub declared_project_dependency: ProjectDependencies, } macro_rules! vec_of_strings { @@ -48,7 +47,6 @@ impl Default for EvaluatorOptions { properties: Default::default(), env: os_env, module_paths: Default::default(), - logger: Default::default(), output_format: Default::default(), allowed_modules, allowed_resources, @@ -63,20 +61,20 @@ impl Default for EvaluatorOptions { } #[derive(Default)] -struct ProjectRemoteDependency { +pub struct ProjectRemoteDependency { package_uri: String, // TODO this should be a path checksums: String, //TODO should this be unified with the msg_api::Checksums type? } #[derive(Default)] -struct ProjectLocalDependency { +pub struct ProjectLocalDependency { package_uri: String, project_file_uri: String, dependencies: ProjectDependencies } #[derive(Default)] -struct ProjectDependencies { +pub struct ProjectDependencies { local_dependencies: HashMap, remote_dependencies: HashMap, } @@ -87,8 +85,6 @@ mod tests { #[test] fn default_options_test() { - let defaults: EvaluatorOptions = Default::default(); - - defaults.logger.trace("hello, ".into(), "world".into()); + let _defaults: EvaluatorOptions = Default::default(); } } diff --git a/pkl-bind/src/evaluator/executor.rs b/pkl-bind/src/evaluator/executor.rs index 9e4fc56..86bb09b 100644 --- a/pkl-bind/src/evaluator/executor.rs +++ b/pkl-bind/src/evaluator/executor.rs @@ -1,6 +1,6 @@ -use std::{process::{Command, Child, Stdio, ChildStdin, ChildStdout}, sync::{mpsc::{Sender, Receiver, channel, RecvError}, atomic::AtomicBool}, os::unix::process::CommandExt, io::{Write, BufReader, BufWriter, Read}, cmp::Reverse, thread::{self, JoinHandle}, time::{Duration, Instant}}; +use std::{process::{Command, Child, Stdio, ChildStdin, ChildStdout}, sync::mpsc::RecvError, io::{Write, Read}}; -use serde::Serialize; +use crate::log; use super::msg_api::{incoming::*, outgoing::*, code::*}; @@ -102,7 +102,7 @@ impl Executor { let mut sender = self.child_in.take().expect("Failed to take"); sender.write_all(&message).expect("Failed to send message"); - // println!("Sent message: {:?}", msg); + // log!(1,"Sent message: {:?}", msg); self.child_in = Some(sender); } @@ -122,45 +122,45 @@ impl Executor { // TODO not very DRY, but this might be the most idiomatic way to use serde match prefix { MessageCode::NewEvaluatorResponse => { - println!("Matched new evaluator, Code: {:02X?}", prefix); //TODO Switch to logging + log!(1,"Matched new evaluator, Code: {:02X?}", prefix); //TODO Switch to logging match rmp_serde::from_read::<_, CreateEvaluatorResponse>(&mut out) { Ok(msg) => value = Some(IncomingMessage::CreateEvaluatorResponse(msg)), - Err(err) => eprintln!("Error decoding the message: {}", err), + Err(err) => log!(1,"Error decoding the message: {}", err), } }, MessageCode::EvaluateResponse => { - println!("Matched new evaluator, Code: {:02X?}", prefix); + log!(1,"Matched new evaluator, Code: {:02X?}", prefix); match rmp_serde::from_read::<_, EvaluateResponse>(&mut out) { Ok(msg) => value = Some(IncomingMessage::EvaluateResponse(msg)), - Err(err) => eprintln!("Error decoding the message: {}", err), + Err(err) => log!(1,"Error decoding the message: {}", err), } }, MessageCode::EvaluateReadModule => { - println!("Matched new evaluator, Code: {:02X?}", prefix); + log!(1,"Matched new evaluator, Code: {:02X?}", prefix); match rmp_serde::from_read::<_, ReadModule>(&mut out) { Ok(msg) => value = Some(IncomingMessage::ReadModule(msg)), - Err(err) => eprintln!("Error decoding the message: {}", err), + Err(err) => log!(1,"Error decoding the message: {}", err), } }, MessageCode::ListResourcesRequest => { - println!("Matched new evaluator, Code: {:02X?}", prefix); + log!(1,"Matched new evaluator, Code: {:02X?}", prefix); match rmp_serde::from_read::<_, ListResources>(&mut out) { Ok(msg) => value = Some(IncomingMessage::ListResources(msg)), - Err(err) => eprintln!("Error decoding the message: {}", err), + Err(err) => log!(1,"Error decoding the message: {}", err), } }, MessageCode::ListModulesRequest => { - println!("Matched new evaluator, Code: {:02X?}", prefix); + log!(1,"Matched new evaluator, Code: {:02X?}", prefix); match rmp_serde::from_read::<_, ListModules>(&mut out) { Ok(msg) => value = Some(IncomingMessage::ListModules(msg)), - Err(err) => eprintln!("Error decoding the message: {}", err), + Err(err) => log!(1,"Error decoding the message: {}", err), } }, MessageCode::EvaluateLog => { - println!("Matched new evaluator, Code: {:02X?}", prefix); + log!(1,"Matched new evaluator, Code: {:02X?}", prefix); match rmp_serde::from_read::<_, Log>(&mut out) { Ok(msg) => value = Some(IncomingMessage::Log(msg)), - Err(err) => eprintln!("Error decoding the message: {}", err), + Err(err) => log!(1,"Error decoding the message: {}", err), } }, _ => { @@ -200,7 +200,7 @@ mod tests { for i in vec { print!("0x{i:02X}, "); } - println!("]"); + log!(1,"]"); } @@ -237,7 +237,7 @@ mod tests { let test1 = pack_message(OutgoingMessage::CreateEvaluator(create_eval)).expect("Failed to pack"); let _ = eval.child_in.take().unwrap().write(&test1.to_vec()); - // println!("Wrote message: {:?}", &test1.to_vec()); + // log!(1,"Wrote message: {:?}", &test1.to_vec()); // print_binary(&test1.to_vec()); let a = eval.child_out.take().unwrap().read_exact(&mut r); // print_binary(&r); @@ -276,7 +276,7 @@ mod tests { // print_binary(&test1); let result = eval.senrec(OutgoingMessage::CreateEvaluator(create_eval)).expect("Failed to accept"); - println!("Received evaluator response: {:?}", result); + log!(1,"Received evaluator response: {:?}", result); } } diff --git a/pkl-bind/src/evaluator/logger.rs b/pkl-bind/src/evaluator/logger.rs index 93990c2..0003945 100644 --- a/pkl-bind/src/evaluator/logger.rs +++ b/pkl-bind/src/evaluator/logger.rs @@ -1,50 +1,92 @@ -use std::io::{self, Write}; - -#[derive(Default)] -pub enum Logger { - #[default] StderrLogger, -} - -#[derive(Default)] -struct StderrLogger {} - -trait LoggerImpl { - fn trace(message: String, frame_uri: String) -> std::io::Result<()>; - fn warn(message: String, frame_uri: String) -> std::io::Result<()>; -} - -impl Logger { - pub fn trace(&self, message: String, frame_uri: String) { - match self { - Logger::StderrLogger => StderrLogger::trace(message, frame_uri).expect("Encountered an IO error in StderrLogger::trace()"), +/// Provides logging support for the pkl library +/// dependent on the environment variable `PKL_DEBUG`. +/// If `PKL_DEBUG=1` then more verbose logging is enabled. +/// without, we still print trace data. +#[macro_export] +macro_rules! log { + // NOTE: this uses a variadic argument system + // copied from the std::fmt eprintln! macro + // see the appropriate documentation + ($l:expr, $($arg:tt)*) => {{ + let key = "PKL_DEBUG"; + match std::env::var(key) { + Ok(val) => { + match val.parse::() { + Ok(v) => { + if v >= $l { + eprintln!($($arg)*); + } + }, + Err(_) => { + if $l == 0 { + eprintln!($($arg)*); + } + } + } + }, + Err(_) => { + if $l == 0 { + eprintln!($($arg)*); + } + }, } - } + }}; +} - pub fn warn(&self, message: String, frame_uri: String) { - match self { - Logger::StderrLogger => StderrLogger::warn(message, frame_uri).expect("Encountered an IO error in StderrLogger::warn()"), +#[macro_export] +macro_rules! plog { + // NOTE: this uses a variadic argument system + // copied from the std::fmt eprintln! macro + // see the appropriate documentation + ($l:expr, $($arg:tt)*) => {{ + let key = "PKL_DEBUG"; + match std::env::var(key) { + Ok(val) => { + match val.parse::() { + Ok(v) => { + if v >= $l { + eprint!($($arg)*); + } + }, + Err(_) => { + if $l == 0 { + eprint!($($arg)*); + } + } + } + }, + Err(_) => { + if $l == 0 { + eprint!($($arg)*); + } + }, } - } + }}; } -impl LoggerImpl for StderrLogger { - fn trace(message: String, frame_uri: String) -> std::io::Result<()> { - let stderr = io::stderr(); - let mut handle = stderr.lock(); +#[cfg(test)] +mod tests { + #[test] + fn test_name() { + log!(1, "this is an unprinted {}", "test"); + } - let s: String = format!("TRACE: {} {}", message, frame_uri); + #[test] + fn test_env_set() { + std::env::set_var("PKL_DEBUG", "1"); - write!(handle, "{}", s)?; - Ok(()) + log!(1, "this is a {} test", "printed"); } - fn warn(message: String, frame_uri: String) -> std::io::Result<()> { - let stderr = io::stderr(); - let mut handle = stderr.lock(); + #[test] + fn test_env_set_no_print() { + std::env::set_var("PKL_DEBUG", "0"); - let s: String = format!("WARN: {} {}", message, frame_uri); + log!(1, "this is still not to print"); + } - write!(handle, "{}", s)?; - Ok(()) + #[test] + fn test_printed_log() { + log!(0, "This should print"); } } diff --git a/pkl-bind/src/evaluator/module_source.rs b/pkl-bind/src/evaluator/module_source.rs index b67e290..8ba3b88 100644 --- a/pkl-bind/src/evaluator/module_source.rs +++ b/pkl-bind/src/evaluator/module_source.rs @@ -2,6 +2,8 @@ use std::{env::current_dir, path::PathBuf}; use url::Url; +use crate::log; + /// Represents a source for Pkl evaluation pub struct ModuleSource { @@ -42,7 +44,7 @@ pub fn file_source(path: PathBuf) -> ModuleSource { if !path.is_absolute() { let pwd: PathBuf = current_dir().expect("Failed to resolve current working dir"); result = pwd.join(&path); - println!("Absolute path: {:?}", result); + log!(1, "Absolute path: {:?}", result); } else { result = path; } diff --git a/pkl-bind/src/evaluator/msg_api/incoming.rs b/pkl-bind/src/evaluator/msg_api/incoming.rs index 78e18a3..b77b921 100644 --- a/pkl-bind/src/evaluator/msg_api/incoming.rs +++ b/pkl-bind/src/evaluator/msg_api/incoming.rs @@ -148,6 +148,8 @@ pub struct Log { #[cfg(test)] mod tests { + use crate::log; + use super::*; #[test] @@ -162,7 +164,7 @@ mod tests { let code = res.0.clone(); let elem = res.1.clone(); - println!("Result of Deserialization: {:?}", res); + log!(1, "Result of Deserialization: {:?}", res); assert_eq!(code, 0x21); assert_eq!(elem.request_id, 135); assert_eq!(elem.evaluator_id, Some(-135901)); @@ -178,7 +180,7 @@ mod tests { let code2 = res.0.clone(); let elem2 = res.1.clone(); - println!("Result of Deserialization: {:?}", res); + log!(1, "Result of Deserialization: {:?}", res); assert_eq!(code2, 0x21); assert_eq!(elem2.request_id, 135); assert_eq!(elem2.evaluator_id, Some(-135901)); diff --git a/pkl-bind/src/evaluator/msg_api/outgoing.rs b/pkl-bind/src/evaluator/msg_api/outgoing.rs index 7ee3c9e..c5ffbcb 100644 --- a/pkl-bind/src/evaluator/msg_api/outgoing.rs +++ b/pkl-bind/src/evaluator/msg_api/outgoing.rs @@ -1,3 +1,6 @@ +/// Utility functions for the outgoing messages _from_ the +/// client (your program) to the server (pkl). + use std::collections::HashMap; use rmp_serde as rmps; @@ -5,7 +8,15 @@ use rmp_serde as rmps; use serde::Serialize; use rmps::Serializer; -use super::code::{CODE_NEW_EVALUATOR, CODE_NEW_EVALUATOR_RESPONSE, CODE_CLOSE_EVALUATOR, CODE_EVALUATE, CODE_EVALUATE_RESPONSE, CODE_EVALUATE_READ_RESPONSE, CODE_EVALUATE_READ_MODULE_RESPONSE, CODE_LIST_RESOURCES_RESPONSE, CODE_LIST_MODULES_REQUEST, CODE_LIST_MODULES_RESPONSE}; +use super::code::{CODE_NEW_EVALUATOR, + CODE_NEW_EVALUATOR_RESPONSE, + CODE_CLOSE_EVALUATOR, + CODE_EVALUATE, + CODE_EVALUATE_RESPONSE, + CODE_EVALUATE_READ_RESPONSE, + CODE_EVALUATE_READ_MODULE_RESPONSE, + CODE_LIST_RESOURCES_RESPONSE, + CODE_LIST_MODULES_RESPONSE}; /// Packs a message in messagepasing v5 format /// @@ -194,6 +205,8 @@ pub struct PathElement { #[cfg(test)] mod tests { + use crate::log; + use super::*; #[test] @@ -217,9 +230,16 @@ mod tests { let mr = ListModulesResponse{request_id: -647892, evaluator_id: -13901, path_elements: vec![pe].into(), error: None}; let mp = pack_message(OutgoingMessage::ListModulesResponse(mr)).unwrap(); - let expected = vec![0x92, 0x2D, 0x83, 0xA9, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x49, 0x64, 0xD2, 0xFF, 0xF6, 0x1D, 0x2C, 0xAB, 0x65, 0x76, 0x61, 0x6C, 0x75, 0x61, 0x74, 0x6F, 0x72, 0x49, 0x64, 0xD1, 0xC9, 0xB3, 0xAC, 0x70, 0x61, 0x74, 0x68, 0x45, 0x6C, 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x91, 0x82, 0xA4, 0x6E, 0x61, 0x6D, 0x65, 0xA7, 0x66, 0x6F, 0x6F, 0x2E, 0x70, 0x6B, 0x6C, 0xAB, 0x69, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6F, 0x72, 0x79, 0xC2]; - - println!("Serialized: {:X?}", mp); + let expected = vec![0x92, 0x2D, 0x83, 0xA9, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x49, 0x64, 0xD2, 0xFF, 0xF6, 0x1D, 0x2C, 0xAB, 0x65, + 0x76, 0x61, 0x6C, 0x75, 0x61, 0x74, 0x6F, 0x72, 0x49, 0x64, + 0xD1, 0xC9, 0xB3, 0xAC, 0x70, 0x61, 0x74, 0x68, 0x45, 0x6C, + 0x65, 0x6D, 0x65, 0x6E, 0x74, 0x73, 0x91, 0x82, 0xA4, 0x6E, + 0x61, 0x6D, 0x65, 0xA7, 0x66, 0x6F, 0x6F, 0x2E, 0x70, 0x6B, + 0x6C, 0xAB, 0x69, 0x73, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x6F, 0x72, 0x79, 0xC2]; + + log!(1, "Serialized: {:X?}", mp); assert_eq!(mp, expected); }