extern crate std;
use nanojson::{Parser};
#[derive(Debug)]
enum Record {
Reading { sensor: SensorId, value: i64 },
Alert { sensor: SensorId, code: i64 },
Heartbeat,
}
#[derive(Debug, PartialEq, Copy, Clone)]
enum SensorId {
Temp,
Humidity,
Unknown,
}
fn copy_str<const N: usize>(s: &str) -> ([u8; N], usize) {
let mut arr = [0u8; N];
let len = s.len().min(N);
arr[..len].copy_from_slice(&s.as_bytes()[..len]);
(arr, len)
}
fn bstr<const N: usize>(arr: &[u8; N], len: usize) -> &str {
core::str::from_utf8(&arr[..len]).unwrap_or("")
}
fn parse_sensor_id(s: &str) -> SensorId {
match s {
"temp" => SensorId::Temp,
"humidity" => SensorId::Humidity,
_ => SensorId::Unknown,
}
}
fn parse_record(json: &mut Parser) -> Record {
let mut type_arr = [0u8; 16]; let mut type_len = 0usize;
let mut sensor_arr= [0u8; 16]; let mut sensor_len= 0usize;
let mut value: Option<i64> = None;
let mut code: Option<i64> = None;
while let Some(key) = json.member().unwrap() {
match key {
"type" => {
let s = json.string().unwrap();
let (a, l) = copy_str::<16>(s);
type_arr = a; type_len = l;
}
"sensor" => {
let s = json.string().unwrap();
let (a, l) = copy_str::<16>(s);
sensor_arr = a; sensor_len = l;
}
"value" => {
value = json.integer().ok();
}
"code" => {
code = json.integer().ok();
}
_ => { json.null().ok(); }
}
}
json.object_end().unwrap();
let type_str = bstr(&type_arr, type_len);
let sensor_str = bstr(&sensor_arr, sensor_len);
match type_str {
"reading" => Record::Reading {
sensor: parse_sensor_id(sensor_str),
value: value.unwrap_or(0),
},
"alert" => Record::Alert {
sensor: parse_sensor_id(sensor_str),
code: code.unwrap_or(0),
},
"heartbeat" => Record::Heartbeat,
other => panic!("unknown record type: {other}"),
}
}
fn print_records(records: &[Option<Record>], count: usize) {
std::println!("Parsed {count} records:");
for i in 0..count {
if let Some(r) = &records[i] {
match r {
Record::Reading { sensor, value } => {
let (int, frac) = (value / 100, value.abs() % 100);
std::println!(" [{i}] Reading {sensor:?}: {int}.{frac:02}");
}
Record::Alert { sensor, code } => {
std::println!(" [{i}] Alert {sensor:?}: code {code}");
}
Record::Heartbeat => {
std::println!(" [{i}] Heartbeat");
}
}
}
}
}
fn main() {
let json = nanojson::stringify_as(|json| {
json.array_begin()?;
json.object_begin()?;
json.member("type").unwrap(); json.string("reading")?;
json.member("sensor").unwrap(); json.string("temp")?;
json.member("value").unwrap(); json.integer(2350)?;
json.object_end()?;
json.object_begin()?;
json.member("type")?; json.string("reading")?;
json.member("sensor")?; json.string("humidity")?;
json.member("value")?; json.integer(6200)?;
json.object_end()?;
json.object_begin()?;
json.member("type")?; json.string("heartbeat")?;
json.object_end()?;
json.object_begin()?;
json.member("type")?; json.string("alert")?;
json.member("sensor")?; json.string("temp")?;
json.member("code")?; json.integer(1)?;
json.object_end()?;
json.array_end()
})
.unwrap();
std::println!("=== std tier ===");
std::println!("Log JSON:\n{}\n", json);
let mut records: [Option<Record>; 8] = [const { None }; 8];
let mut count = 0usize;
nanojson::parse_as(json.as_bytes(), |json| {
json.array_begin()?;
while json.array_item()? {
json.object_begin()?;
records[count] = Some(parse_record(json));
count += 1;
}
json.array_end()?;
Ok(())
})
.unwrap();
print_records(&records, count);
std::println!("\n=== no_std tier ===");
let mut buf = [0; 512];
let log = nanojson::stringify_sized_as(&mut buf, |json| {
json.array_begin()?;
json.object_begin()?;
json.member("type")?; json.string("reading")?;
json.member("sensor")?; json.string("temp")?;
json.member("value")?; json.integer(2350)?;
json.object_end()?;
json.object_begin()?;
json.member("type")?; json.string("reading")?;
json.member("sensor")?; json.string("humidity")?;
json.member("value")?; json.integer(6200)?;
json.object_end()?;
json.object_begin()?;
json.member("type")?; json.string("heartbeat")?;
json.object_end()?;
json.object_begin()?;
json.member("type")?; json.string("alert")?;
json.member("sensor")?; json.string("temp")?;
json.member("code")?; json.integer(1)?;
json.object_end()?;
json.array_end()
})
.unwrap();
std::println!("Log JSON ({} bytes):\n{}\n", log.len(), log);
let mut records: [Option<Record>; 8] = [const { None }; 8];
let mut count = 0usize;
let mut str_buf = [0u8; 32];
let mut json = Parser::new(log.as_bytes(), &mut str_buf);
json.array_begin().unwrap();
while json.array_item().unwrap() {
json.object_begin().unwrap();
records[count] = Some(parse_record(&mut json));
count += 1;
}
json.array_end().unwrap();
print_records(&records, count);
let n = nanojson::measure(|json| {
json.object_begin()?;
json.member("type")?; json.string("reading")?;
json.member("sensor")?; json.string("temp")?;
json.member("value")?; json.integer(2350)?;
json.object_end()
});
std::println!("\nA 'reading' record is {n} bytes when serialized.");
}
#[cfg(test)] #[test] fn test_main() { main() }