Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The purpose of this changelog is to document new features and breaking changes t
- Add JSON <-> Scheme interface
- Separate crypto primitives into separate namespace
- Add unix time primitive
- Use explicit period instead of periodicity

--- v1.0.4 (2025.09.14) ---

Expand Down
6 changes: 3 additions & 3 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ pub struct Config {
#[arg(
short = 'c',
long,
default_value_t = 0,
help = "Power of two determining the period of the step query"
default_value_t = 1.0,
help = "Number of seconds between each step inquiry"
)]
pub periodicity: i32,
pub period: f64,
}

impl Config {
Expand Down
176 changes: 81 additions & 95 deletions src/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,16 @@ impl Type {

pub fn obj2str(sc: *mut s7_scheme, obj: *mut s7_cell) -> String {
unsafe {
unsafe {
let expr = s7_object_to_c_string(sc, obj);
let cstr = CStr::from_ptr(expr);
let result = match cstr.to_str() {
Ok(expr) => expr.to_owned(),
Err(_) => format!("(error 'encoding-error \"Failed to encode string\")"),
};
free(expr as *mut libc::c_void);
result
}
let expr = s7_string(s7_object_to_string(sc, obj, false));
let cstr = CStr::from_ptr(expr);
let result = match cstr.to_str() {
Ok(rust_str) => match s7_is_string(obj) {
true => format!("\"{}\"", rust_str),
false => format!("{}", rust_str.to_owned()),
},
Err(_) => format!("(error 'encoding-error \"Failed to encode string\")"),
};
result
}
}

Expand All @@ -108,36 +108,32 @@ pub fn scheme2json(expression: &str) -> Result<Value, String> {
// - @hash-table: {"*type/hash-table*": [["a", 6], [53, 199]]}

unsafe {
unsafe {
let sc: *mut s7_scheme = s7_init();
let sc: *mut s7_scheme = s7_init();

// Parse the expression without evaluating it
let c_expr = CString::new(expression).unwrap_or_else(|_| CString::new("()").unwrap());
let input_port = s7_open_input_string(sc, c_expr.as_ptr());
let s7_obj = s7_read(sc, input_port);
s7_close_input_port(sc, input_port);
// Parse the expression without evaluating it
let c_expr = CString::new(expression).unwrap_or_else(|_| CString::new("()").unwrap());
let input_port = s7_open_input_string(sc, c_expr.as_ptr());
let s7_obj = s7_read(sc, input_port);
s7_close_input_port(sc, input_port);

let result = s7_obj_to_json(sc, s7_obj);
s7_free(sc);
result
}
let result = s7_obj_to_json(sc, s7_obj);
s7_free(sc);
result
}
}

pub fn json2scheme(expression: Value) -> Result<String, String> {
unsafe {
unsafe {
let sc: *mut s7_scheme = s7_init();
match json_to_s7_obj(sc, &expression) {
Ok(s7_obj) => {
let result = obj2str(sc, s7_obj);
s7_free(sc);
Ok(result)
}
Err(err) => {
s7_free(sc);
Err(err)
}
let sc: *mut s7_scheme = s7_init();
match json_to_s7_obj(sc, &expression) {
Ok(s7_obj) => {
let result = obj2str(sc, s7_obj);
s7_free(sc);
Ok(result)
}
Err(err) => {
s7_free(sc);
Err(err)
}
}
}
Expand All @@ -163,52 +159,50 @@ impl Evaluator {
primitives_.extend(primitives);

unsafe {
unsafe {
let sc: *mut s7_scheme = s7_init();

// remove insecure primitives
for primitive in REMOVE {
s7_define(
sc,
s7_rootlet(sc),
s7_make_symbol(sc, primitive.as_ptr()),
s7_make_symbol(sc, c"*removed*".as_ptr()),
);
}
let sc: *mut s7_scheme = s7_init();

// add new types
for (&tag_, type_) in types.iter() {
let tag = s7_make_c_type(sc, type_.name.as_ptr());
assert!(tag == tag_, "Type tag was not properly set");
s7_c_type_set_gc_free(sc, tag, Some(type_.free));
s7_c_type_set_gc_mark(sc, tag, Some(type_.mark));
s7_c_type_set_is_equal(sc, tag, Some(type_.is_equal));
s7_c_type_set_to_string(sc, tag, Some(type_.to_string));
}
// remove insecure primitives
for primitive in REMOVE {
s7_define(
sc,
s7_rootlet(sc),
s7_make_symbol(sc, primitive.as_ptr()),
s7_make_symbol(sc, c"*removed*".as_ptr()),
);
}

// add new primitives
for primitive in primitives_.iter() {
s7_define_function(
sc,
primitive.name.as_ptr(),
Some(primitive.code),
primitive
.args_required
.try_into()
.expect("args_required conversion failed"),
primitive
.args_optional
.try_into()
.expect("args_optional conversion failed"),
primitive.args_rest,
primitive.description.as_ptr(),
);
}
// add new types
for (&tag_, type_) in types.iter() {
let tag = s7_make_c_type(sc, type_.name.as_ptr());
assert!(tag == tag_, "Type tag was not properly set");
s7_c_type_set_gc_free(sc, tag, Some(type_.free));
s7_c_type_set_gc_mark(sc, tag, Some(type_.mark));
s7_c_type_set_is_equal(sc, tag, Some(type_.is_equal));
s7_c_type_set_to_string(sc, tag, Some(type_.to_string));
}

Self {
// add new primitives
for primitive in primitives_.iter() {
s7_define_function(
sc,
primitives: primitives_,
}
primitive.name.as_ptr(),
Some(primitive.code),
primitive
.args_required
.try_into()
.expect("args_required conversion failed"),
primitive
.args_optional
.try_into()
.expect("args_optional conversion failed"),
primitive.args_rest,
primitive.description.as_ptr(),
);
}

Self {
sc,
primitives: primitives_,
}
}
}
Expand All @@ -233,9 +227,7 @@ impl Evaluator {
impl Drop for Evaluator {
fn drop(&mut self) {
unsafe {
unsafe {
s7_free(self.sc);
}
s7_free(self.sc);
}
}
}
Expand All @@ -244,19 +236,14 @@ fn primitive_expression_to_byte_vector() -> Primitive {
unsafe extern "C" fn code(sc: *mut s7_scheme, args: s7_pointer) -> s7_pointer {
let arg = s7_car(args);

let s7_c_str = s7_object_to_c_string(sc, arg);
let c_string = CStr::from_ptr(s7_c_str);
// let s7_c_str = s7_string(s7_object_to_string(sc, arg, false));
// let c_string = CStr::from_ptr(s7_c_str);
let bytes = obj2str(sc, arg).into_bytes();

let bv = s7_make_byte_vector(
sc,
c_string.to_bytes().len() as i64,
1 as i64,
std::ptr::null_mut(),
);
for (i, b) in c_string.to_bytes().iter().enumerate() {
let bv = s7_make_byte_vector(sc, bytes.len() as i64, 1 as i64, std::ptr::null_mut());
for (i, b) in bytes.iter().enumerate() {
s7_byte_vector_set(bv, i as i64, *b);
}
free(s7_c_str as *mut libc::c_void);
bv
}

Expand Down Expand Up @@ -328,18 +315,16 @@ fn primitive_hex_string_to_byte_vector() -> Primitive {
);
}

let s7_c_str = s7_object_to_c_string(sc, arg);
let s7_c_str = s7_string(s7_object_to_string(sc, arg, false));
let hex_string = CStr::from_ptr(s7_c_str)
.to_str()
.expect("Failed to convert C string to hex string");

let result: Result<Vec<u8>, ParseIntError> = (1..hex_string.len() - 1)
let result: Result<Vec<u8>, ParseIntError> = (0..hex_string.len())
.step_by(2)
.map(|i| u8::from_str_radix(&hex_string[i..i + 2], 16))
.collect();

free(s7_c_str as *mut libc::c_void);

match result {
Ok(result) => {
let bv =
Expand Down Expand Up @@ -527,14 +512,15 @@ unsafe fn s7_obj_to_json(sc: *mut s7_scheme, obj: s7_pointer) -> Result<Value, S
Err("Invalid floating point number - cannot convert to JSON".to_string())
}
} else if s7_is_string(obj) {
let c_str = s7_string(obj);
let rust_str = CStr::from_ptr(c_str).to_string_lossy();
// let c_str = s7_string(obj);
// let rust_str = CStr::from_ptr(c_str).to_string_lossy();
let rust_str = obj2str(sc, obj);

// Check if it's a special type marker
let mut special_type = Map::new();
special_type.insert(
"*type/string*".to_string(),
Value::String(rust_str.to_string()),
Value::String(String::from(&rust_str[1..(rust_str.len() - 1)])),
);
Ok(Value::Object(special_type))
} else if s7_is_symbol(obj) {
Expand Down
8 changes: 3 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,21 +117,19 @@ async fn main() {
rocket_config.address = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0));
rocket_config.limits = Limits::new().limit("string", 1_i32.mebibytes());

let period = 2_f64.powi(config.periodicity);

if config.step != "" {
tokio::spawn(async move {
let mut step = 0;
let start = ((SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Failed to get system time")
.as_micros() as f64
/ (period * MICRO))
/ (config.period * MICRO))
.ceil()
* (period * MICRO)) as u128;
* (config.period * MICRO)) as u128;

loop {
let until = start + step * (period * MICRO) as u128;
let until = start + step * (config.period * MICRO) as u128;
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Failed to get system time")
Expand Down
Loading