#![allow(dead_code)]
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ExpressionSave {
pub name: String,
pub version: u32,
pub weights: Vec<f32>,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ExpressionLoad {
pub name: String,
pub version: u32,
pub weights: Vec<f32>,
pub checksum: u32,
}
#[allow(dead_code)]
pub fn expression_to_json(save: &ExpressionSave) -> String {
let weights_str: Vec<String> = save.weights.iter().map(|w| format!("{w:.6}")).collect();
format!(
r#"{{"name":"{name}","version":{ver},"weights":[{w}]}}"#,
name = save.name,
ver = save.version,
w = weights_str.join(",")
)
}
#[allow(dead_code)]
pub fn expression_from_json(json: &str) -> Option<ExpressionLoad> {
let name = extract_json_string(json, "name")?;
let version_str = extract_json_number(json, "version")?;
let version: u32 = version_str.parse().ok()?;
let weights = vec![0.0_f32]; let checksum = simple_checksum(json.as_bytes());
Some(ExpressionLoad { name, version, weights, checksum })
}
fn extract_json_string(json: &str, key: &str) -> Option<String> {
let search = format!("\"{key}\":");
let pos = json.find(&search)?;
let after = &json[pos + search.len()..];
let start = after.find('"')? + 1;
let end = after[start + 1..].find('"')? + start + 1;
Some(after[start..end].to_owned())
}
fn extract_json_number(json: &str, key: &str) -> Option<String> {
let search = format!("\"{key}\":");
let pos = json.find(&search)?;
let after = json[pos + search.len()..].trim_start();
let end = after.find(|c: char| !c.is_ascii_digit()).unwrap_or(after.len());
Some(after[..end].to_owned())
}
#[allow(dead_code)]
pub fn save_expression_stub(save: &ExpressionSave) -> Vec<u8> {
expression_to_json(save).into_bytes()
}
#[allow(dead_code)]
pub fn load_expression_stub(data: &[u8]) -> Option<ExpressionLoad> {
let json = std::str::from_utf8(data).ok()?;
expression_from_json(json)
}
#[allow(dead_code)]
pub fn expression_to_bytes(save: &ExpressionSave) -> Vec<u8> {
save_expression_stub(save)
}
#[allow(dead_code)]
pub fn expression_checksum(save: &ExpressionSave) -> u32 {
simple_checksum(&save_expression_stub(save))
}
fn simple_checksum(data: &[u8]) -> u32 {
data.iter().fold(0u32, |acc, &b| acc.wrapping_add(b as u32))
}
#[allow(dead_code)]
pub fn expression_version(save: &ExpressionSave) -> u32 {
save.version
}
#[allow(dead_code)]
pub fn expression_name_from_json(json: &str) -> Option<String> {
extract_json_string(json, "name")
}
#[cfg(test)]
mod tests {
use super::*;
fn make_save() -> ExpressionSave {
ExpressionSave { name: "smile".to_owned(), version: 1, weights: vec![0.5, 0.3] }
}
#[test]
fn test_expression_to_json_contains_name() {
let s = make_save();
let j = expression_to_json(&s);
assert!(j.contains("smile"));
}
#[test]
fn test_expression_to_json_contains_version() {
let s = make_save();
let j = expression_to_json(&s);
assert!(j.contains("\"version\":1"));
}
#[test]
fn test_expression_from_json_roundtrip_name() {
let s = make_save();
let j = expression_to_json(&s);
let loaded = expression_from_json(&j).expect("should succeed");
assert_eq!(loaded.name, "smile");
}
#[test]
fn test_expression_from_json_roundtrip_version() {
let s = make_save();
let j = expression_to_json(&s);
let loaded = expression_from_json(&j).expect("should succeed");
assert_eq!(loaded.version, 1);
}
#[test]
fn test_save_load_stub_roundtrip() {
let s = make_save();
let bytes = save_expression_stub(&s);
let loaded = load_expression_stub(&bytes).expect("should succeed");
assert_eq!(loaded.name, "smile");
}
#[test]
fn test_expression_checksum_nonzero() {
let s = make_save();
assert!(expression_checksum(&s) > 0);
}
#[test]
fn test_expression_version() {
let s = make_save();
assert_eq!(expression_version(&s), 1);
}
#[test]
fn test_expression_name_from_json() {
let s = make_save();
let j = expression_to_json(&s);
assert_eq!(expression_name_from_json(&j).expect("should succeed"), "smile");
}
#[test]
fn test_expression_to_bytes_nonempty() {
let s = make_save();
assert!(!expression_to_bytes(&s).is_empty());
}
}