Skip to content

Instantly share code, notes, and snippets.

@yuriks
Forked from anonymous/playground.rs
Created April 17, 2017 06:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yuriks/879fdb95429c9c5feb7f3d6bca55bce3 to your computer and use it in GitHub Desktop.
Save yuriks/879fdb95429c9c5feb7f3d6bca55bce3 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
const TEST_DATA : &'static str = "Device: ID=1; Fw=16071801; Evt=2; Alarms: CoilRevesed=OFF; Power: Active=1753W; Reactive=279var; Appearent=403VA; Line: Current=7.35900021; Voltage=230.08V; Phase=-43,841rad; Peaks: 7.33199978;7.311999799999999;7.53000021;7.48400021;7.54300022;7.62900019;7.36499977;7.28599977;7.37200022;7.31899977; FFT Re: 9748;46;303;33;52;19;19;39;-455; FFT Img: 2712;6;-792;-59;1386;-19;963;33;462; UTC Time: 2016-10-4 16:47:50; hz: 49.87; WiFi Strength: -62; Dummy: 20";
fn partition(s: &str) -> (&str, Option<char>, &str) {
const TOKEN_SEPARATORS : &'static [char] = &[':', '=', ';'];
let idx = s.find(TOKEN_SEPARATORS).unwrap_or(s.len());
let (head, tail) = s.split_at(idx);
let mut tail_it = tail.chars();
let separator = tail_it.next();
(head, separator, tail_it.as_str())
}
#[derive(Debug, Eq, PartialEq)]
enum Token<'a> {
SectionName(&'a str),
AttributeName(&'a str),
Value(&'a str),
}
fn get_next_token<'a>(s: &mut &'a str) -> Token<'a> {
let (value, sep, rest) = partition(s);
let trimmed = value.trim();
*s = rest;
match sep {
Some(':') => Token::SectionName(trimmed),
Some('=') => Token::AttributeName(trimmed),
Some(';') | None => Token::Value(trimmed),
_ => unreachable!()
}
}
pub type Values<'a> = Vec<&'a str>;
#[derive(Debug)]
pub struct Attribute<'a> {
key: &'a str,
values: Values<'a>,
}
#[derive(Debug)]
pub struct Section<'a> {
key: &'a str,
values: Values<'a>,
attribs: Vec<Attribute<'a>>,
}
#[derive(Debug)]
pub struct Event<'a> {
sections: Vec<Section<'a>>,
}
pub fn parse_event_string(mut s: & str) -> Event {
#[inline(always)]
fn pop_attribute<'a>(
section: &mut Section<'a>,
attribute: &mut Option<Attribute<'a>>) {
if let Some(attribute) = attribute.take() {
section.attribs.push(attribute);
}
}
#[inline(always)]
fn pop_section<'a>(
sections: &mut Vec<Section<'a>>,
section: &mut Option<Section<'a>>,
attribute: &mut Option<Attribute<'a>>) {
if let Some(mut section) = section.take() {
pop_attribute(&mut section, attribute);
sections.push(section);
}
}
let mut sections = vec![];
let mut section = None;
let mut attribute = None;
while !s.is_empty() {
match get_next_token(&mut s) {
Token::SectionName(name) => {
pop_section(&mut sections, &mut section, &mut attribute);
section = Some(Section {
key: name,
values: vec![],
attribs: vec![],
});
},
Token::AttributeName(name) => {
let section = section.as_mut().expect("Missing section");
pop_attribute(section, &mut attribute);
attribute = Some(Attribute {
key: name,
values: vec![],
});
}
Token::Value(value) => {
if let Some(ref mut attribute) = attribute {
attribute.values.push(value);
} else if let Some(ref mut section) = section {
section.values.push(value);
} else {
panic!("Missing section");
}
}
}
}
pop_section(&mut sections, &mut section, &mut attribute);
Event { sections: sections }
}
mod tests {
use super::*;
fn partition_splits_at_character() {
assert_eq!(partition("abá=123; xxx"), ("abá", Some('='), "123; xxx"));
}
fn partition_splits_at_eof() {
assert_eq!(partition("abá"), ("abá", None, ""));
}
fn token_retrieves_tokens() {
let mut s = "Section Name: Attrib Name=5W;6.4";
assert_eq!(get_next_token(&mut s), Token::SectionName("Section Name"));
assert_eq!(get_next_token(&mut s), Token::AttributeName("Attrib Name"));
assert_eq!(get_next_token(&mut s), Token::Value("5W"));
assert_eq!(get_next_token(&mut s), Token::Value("6.4"));
assert_eq!(s, "");
}
fn parse_event_string_works_on_small_input() {
let input = "Section Name: Attrib Name=5W;6.4";
let event = parse_event_string(&input);
println!("small:\n{:?}", event);
}
fn parse_event_string_works_on_large_input() {
let event = parse_event_string(&TEST_DATA);
println!("large:\n{:?}", event);
}
// Work-around for playground
pub fn invoke_all() {
partition_splits_at_character();
partition_splits_at_eof();
token_retrieves_tokens();
parse_event_string_works_on_small_input();
parse_event_string_works_on_large_input();
}
}
fn main() {
tests::invoke_all();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment