I have a data structure used to make a tree representing data brought in from an existing serialized format.
#[derive(Debug, Clone, PartialEq, EnumAsInner)]
pub enum LLSDValue {
Undefined,
Boolean(bool),
Real(f64),
Integer(i32),
UUID(uuid::Uuid),
String(String),
Date(i64),
URI(String),
Binary(Vec<u8>),
Map(HashMap<String, LLSDValue>),
Array(Vec<LLSDValue>),
}
Parsing into that format is straightforward, as is seralizing it. I've written a crate for that.
Getting data from that data structure, though, is a a pain. That requires code like this:
let id = innermap
.get("ID").ok_or_else(|| anyhow!("Expected 'ID'"))?
.as_binary().ok_or_else(|| anyhow!("Expected ID byte Array"))?
.clone()
.try_into().map_err(|e| anyhow!("Expected 16 byte array, error{:?}",e))?;
All this is doing is taking a value of the form
Map("ID" : [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
and returning an array of 16 bytes. I didn't want to use "unwrap" because then mis-formatted external data could crash the program. I'm using the enum_as_inner crate to create the accessor .as_binary().
The problem is that there's nothing concise like "?" for functions such as hashmap.get() which return None on failure. So I have to write out the whole "ok_or_else" boilerplate, plus a closure, plus a call to "anyhow!". ok_or_else is supposed to be lazily evaluated. I hope.
The "json" crate has a less verbose approach. All their accessors return something like "JsonNone" on fail, and "JsonNone" accepts all the accessors. So JsonNone propagates all the way to the end of the expression, where it can be detected and ejected.
That requires building more machinery into the type. This is a very simple enum type, and accessing it should be equally simple. The verbosity above works fine, but seems excessive.