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, buf: &mut [u8]) -> 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.object_member(buf).unwrap() {
let (karr, klen) = copy_str::<16>(key);
match bstr(&karr, klen) {
"type" => {
let s = json.string(buf).unwrap();
let (a, l) = copy_str::<16>(s);
type_arr = a; type_len = l;
}
"sensor" => {
let s = json.string(buf).unwrap();
let (a, l) = copy_str::<16>(s);
sensor_arr = a; sensor_len = l;
}
"value" => {
value = Some(json.number_str().unwrap().parse().unwrap());
}
"code" => {
code = Some(json.number_str().unwrap().parse().unwrap());
}
_ => { 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_manual(|json| {
json.array_begin()?;
json.object_begin()?;
json.member_key("type").unwrap(); json.string("reading")?;
json.member_key("sensor").unwrap(); json.string("temp")?;
json.member_key("value").unwrap(); json.integer(2350)?;
json.object_end()?;
json.object_begin()?;
json.member_key("type")?; json.string("reading")?;
json.member_key("sensor")?; json.string("humidity")?;
json.member_key("value")?; json.integer(6200)?;
json.object_end()?;
json.object_begin()?;
json.member_key("type")?; json.string("heartbeat")?;
json.object_end()?;
json.object_begin()?;
json.member_key("type")?; json.string("alert")?;
json.member_key("sensor")?; json.string("temp")?;
json.member_key("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_manual(json.as_bytes(), |json, buf| {
json.array_begin()?;
while json.array_item()? {
json.object_begin()?;
records[count] = Some(parse_record(json, buf));
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_manual_sized(&mut buf, |json| {
json.array_begin()?;
json.object_begin()?;
json.member_key("type")?; json.string("reading")?;
json.member_key("sensor")?; json.string("temp")?;
json.member_key("value")?; json.integer(2350)?;
json.object_end()?;
json.object_begin()?;
json.member_key("type")?; json.string("reading")?;
json.member_key("sensor")?; json.string("humidity")?;
json.member_key("value")?; json.integer(6200)?;
json.object_end()?;
json.object_begin()?;
json.member_key("type")?; json.string("heartbeat")?;
json.object_end()?;
json.object_begin()?;
json.member_key("type")?; json.string("alert")?;
json.member_key("sensor")?; json.string("temp")?;
json.member_key("code")?; json.integer(1)?;
json.object_end()?;
json.array_end()
})
.unwrap();
std::println!("Log JSON ({} bytes):\n{}\n", log.len(), core::str::from_utf8(log).unwrap());
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);
json.array_begin().unwrap();
while json.array_item().unwrap() {
json.object_begin().unwrap();
records[count] = Some(parse_record(&mut json, &mut str_buf));
count += 1;
}
json.array_end().unwrap();
print_records(&records, count);
let n = nanojson::measure(|json| {
json.object_begin()?;
json.member_key("type")?; json.string("reading")?;
json.member_key("sensor")?; json.string("temp")?;
json.member_key("value")?; json.integer(2350)?;
json.object_end()
});
std::println!("\nA 'reading' record is {n} bytes when serialized.");
}