13 releases (8 breaking)
0.9.4 | Jan 11, 2024 |
---|---|
0.9.3 | Dec 23, 2022 |
0.9.2 | Jan 31, 2022 |
0.9.1 | Feb 14, 2021 |
0.3.0 | Jul 24, 2020 |
#91 in Network programming
94,066 downloads per month
Used in 29 crates
(6 directly)
100KB
2K
SLoC
Structured Field Values for HTTP
sfv
crate is an implementation of Structured Field Values for HTTP as specified in RFC 8941 for parsing and serializing HTTP field values (also known as "structured headers" or "structured trailers").
It also exposes a set of types that might be useful for defining new structured fields.
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
lib.rs
:
sfv
crate is an implementation of Structured Field Values for HTTP as specified in RFC 8941 for parsing and serializing HTTP field values.
It also exposes a set of types that might be useful for defining new structured fields.
Data Structures
There are three types of structured fields:
Item
- can be anInteger
,Decimal
,String
,Token
,Byte Sequence
, orBoolean
. It can have associatedParameters
.List
- array of zero or more members, each of which can be anItem
or anInnerList
, both of which can beParameterized
.Dictionary
- ordered map of name-value pairs, where the names are short textual strings and the values areItems
or arrays ofItems
(represented withInnerList
), both of which can beParameterized
. There can be zero or more members, and their names are unique in the scope of theDictionary
they occur within.
There's also a few primitive types used to construct structured field values:
BareItem
used asItem
's value or as a parameter value inParameters
.Parameters
are an ordered map of key-value pairs that are associated with anItem
orInnerList
. The keys are unique within the scope theParameters
they occur within, and the values areBareItem
.InnerList
is an array of zero or moreItems
. Can haveParameters
.ListEntry
represents eitherItem
orInnerList
as a member ofList
or as member-value inDictionary
.
Examples
Parsing
use sfv::Parser;
// Parsing structured field value of Item type.
let item_header_input = "12.445;foo=bar";
let item = Parser::parse_item(item_header_input.as_bytes());
assert!(item.is_ok());
println!("{:#?}", item);
// Parsing structured field value of List type.
let list_header_input = "1;a=tok, (\"foo\" \"bar\");baz, ()";
let list = Parser::parse_list(list_header_input.as_bytes());
assert!(list.is_ok());
println!("{:#?}", list);
// Parsing structured field value of Dictionary type.
let dict_header_input = "a=?0, b, c; foo=bar, rating=1.5, fruits=(apple pear)";
let dict = Parser::parse_dictionary(dict_header_input.as_bytes());
assert!(dict.is_ok());
println!("{:#?}", dict);
Getting Parsed Value Members
use sfv::*;
let dict_header = "u=2, n=(* foo 2)";
let dict = Parser::parse_dictionary(dict_header.as_bytes()).unwrap();
// Case 1 - handling value if it's an Item of Integer type
let u_val = match dict.get("u") {
Some(ListEntry::Item(item)) => item.bare_item.as_int(),
_ => None,
};
if let Some(u_val) = u_val {
println!("{}", u_val);
}
// Case 2 - matching on all possible types
match dict.get("u") {
Some(ListEntry::Item(item)) => match &item.bare_item {
BareItem::Token(val) => {
// do something if it's a Token
println!("{}", val);
}
BareItem::Integer(val) => {
// do something if it's an Integer
println!("{}", val);
}
BareItem::Boolean(val) => {
// do something if it's a Boolean
println!("{}", val);
}
BareItem::Decimal(val) => {
// do something if it's a Decimal
println!("{}", val);
}
BareItem::String(val) => {
// do something if it's a String
println!("{}", val);
}
BareItem::ByteSeq(val) => {
// do something if it's a ByteSeq
println!("{:?}", val);
}
},
Some(ListEntry::InnerList(inner_list)) => {
// do something if it's an InnerList
println!("{:?}", inner_list.items);
}
None => panic!("key not found"),
}
Structured Field Value Construction and Serialization
Creates Item
with empty parameters:
use sfv::{Item, BareItem, SerializeValue};
let str_item = Item::new(BareItem::String(String::from("foo")));
assert_eq!(str_item.serialize_value().unwrap(), "\"foo\"");
Creates Item
field value with parameters:
use sfv::{Item, BareItem, SerializeValue, Parameters, Decimal, FromPrimitive};
let mut params = Parameters::new();
let decimal = Decimal::from_f64(13.45655).unwrap();
params.insert("key".into(), BareItem::Decimal(decimal));
let int_item = Item::with_params(BareItem::Integer(99), params);
assert_eq!(int_item.serialize_value().unwrap(), "99;key=13.457");
Creates List
field value with Item
and parametrized InnerList
as members:
use sfv::{Item, BareItem, InnerList, List, SerializeValue, Parameters};
let tok_item = BareItem::Token("tok".into());
// Creates Item.
let str_item = Item::new(BareItem::String(String::from("foo")));
// Creates InnerList members.
let mut int_item_params = Parameters::new();
int_item_params.insert("key".into(), BareItem::Boolean(false));
let int_item = Item::with_params(BareItem::Integer(99), int_item_params);
// Creates InnerList.
let mut inner_list_params = Parameters::new();
inner_list_params.insert("bar".into(), BareItem::Boolean(true));
let inner_list = InnerList::with_params(vec![int_item, str_item], inner_list_params);
let list: List = vec![Item::new(tok_item).into(), inner_list.into()];
assert_eq!(
list.serialize_value().unwrap(),
"tok, (99;key=?0 \"foo\");bar"
);
Creates Dictionary
field value:
use sfv::{Parser, Item, BareItem, SerializeValue, ParseValue, Dictionary};
let member_value1 = Item::new(BareItem::String(String::from("apple")));
let member_value2 = Item::new(BareItem::Boolean(true));
let member_value3 = Item::new(BareItem::Boolean(false));
let mut dict = Dictionary::new();
dict.insert("key1".into(), member_value1.into());
dict.insert("key2".into(), member_value2.into());
dict.insert("key3".into(), member_value3.into());
assert_eq!(
dict.serialize_value().unwrap(),
"key1=\"apple\", key2, key3=?0"
);
Dependencies
~1.5MB
~27K SLoC