diff options
author | Guillaume Pasquet <dev@etenil.net> | 2021-11-14 22:50:17 +0000 |
---|---|---|
committer | Guillaume Pasquet <dev@etenil.net> | 2021-11-14 22:50:17 +0000 |
commit | c9486ece952d2e07a78192a9ae0e7764fdee4164 (patch) | |
tree | 1fd086959e4fc7cbe52a1228acfa1b62cc26ac38 /src | |
parent | fce52576205ebbb6b03a466b8f9a137c45420fde (diff) |
First working version of the barbfile parser
Diffstat (limited to 'src')
-rw-r--r-- | src/barbfile.rs | 168 | ||||
-rw-r--r-- | src/main.rs | 9 |
2 files changed, 177 insertions, 0 deletions
diff --git a/src/barbfile.rs b/src/barbfile.rs new file mode 100644 index 0000000..be7cead --- /dev/null +++ b/src/barbfile.rs @@ -0,0 +1,168 @@ +use std::matches; +use std::str::FromStr; +use std::{error::Error, fmt}; + +#[derive(Debug)] +struct BarbParseError {} + +impl Error for BarbParseError {} + +impl fmt::Display for BarbParseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Error parsing barb file") + } +} + +enum Method { + GET, + PUT, + POST, + PATCH, + DELETE, +} + +impl FromStr for Method { + type Err = BarbParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + match s { + "GET" => Ok(Self::GET), + "PUT" => Ok(Self::PUT), + "POST" => Ok(Self::POST), + "PATCH" => Ok(Self::PATCH), + "DELETE" => Ok(Self::DELETE), + _ => Err(BarbParseError {}), + } + } +} + +#[derive(Debug)] +struct Header { + name: String, + value: String, +} + +impl fmt::Display for Header { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}: {}", self.name, self.value) + } +} + +struct BarbHeader { + pub method: Method, + pub url: String, + pub headers: Vec<Header>, + pub filter: Option<String>, +} + +impl BarbHeader { + fn new(method: Method, url: String, headers: Vec<Header>, filter: Option<String>) -> Self { + BarbHeader { + method: method, + url: url, + headers: headers, + filter: filter, + } + } +} + +struct BarbFile { + header: BarbHeader, + body: Option<String>, +} + +fn decode_url_line(line: &str) -> Result<(Method, String), BarbParseError> { + let mut components = line[1..].split('^'); + let meth = components.next().ok_or(BarbParseError {})?; + let url = components.next().ok_or(BarbParseError {})?; + return Ok((Method::from_str(meth)?, String::from(url))); +} + +fn decode_header(line: &str) -> Result<Header, BarbParseError> { + let mut components = line[1..].split(':'); + let header_name = components.next().ok_or(BarbParseError {})?; + let header_val = components.next().ok_or(BarbParseError {})?.trim(); + Ok(Header { + name: String::from(header_name), + value: String::from(header_val), + }) +} + +impl FromStr for BarbFile { + type Err = BarbParseError; + + fn from_str(s: &str) -> Result<Self, Self::Err> { + let mut lines = s.split('\n'); + let (method, url) = decode_url_line(lines.next().ok_or(BarbParseError {})?)?; + let mut headers: Vec<Header> = vec![]; + let mut filter = None; + for line in lines { + if !matches!(line.chars().nth(0), Some('#')) { + break; // Reached the end of the header. + } + + if let Some(_) = line.find(':') { + headers.push(decode_header(line).unwrap()); + } + + if let None = filter { + filter = match &line[0..2] { + "#|" => Some(String::from(&line[2..])), + _ => None, + } + } + } + + Ok(BarbFile { + header: BarbHeader::new(method, url, headers, filter), + body: None, + }) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_method_from_str() { + assert!(matches!(Method::from_str("GET").unwrap(), Method::GET)); + assert!(matches!(Method::from_str("GET").unwrap(), Method::GET)); + assert!(matches!(Method::from_str("PUT").unwrap(), Method::PUT)); + assert!(matches!(Method::from_str("POST").unwrap(), Method::POST)); + assert!(matches!(Method::from_str("PATCH").unwrap(), Method::PATCH)); + assert!(matches!( + Method::from_str("DELETE").unwrap(), + Method::DELETE + )); + } + + #[test] + fn test_decode_url_line() { + let (method, url) = decode_url_line("#GET^http://blahblah").unwrap(); + assert!(matches!(method, Method::GET)); + assert_eq!(url, "http://blahblah"); + } + + #[test] + fn test_decode_header() { + let hdr = decode_header("#Authorization: TOKEN 12345").unwrap(); + assert_eq!(hdr.name, "Authorization"); + assert_eq!(hdr.value, "TOKEN 12345"); + } + + #[test] + fn test_parse_barbfile() { + let barbfile = + BarbFile::from_str("#GET^https://blah.com/api/blah\n#Authorization: BLAH\n#|filtr\n") + .unwrap(); + assert_eq!(barbfile.body, None); + assert!(matches!(barbfile.header.method, Method::GET)); + assert_eq!(barbfile.header.url, "https://blah.com/api/blah"); + assert_eq!(barbfile.header.filter, Some(String::from("filtr"))); + println!("{:?}", barbfile.header.headers); + assert_eq!(barbfile.header.headers.len(), 1); + assert_eq!(barbfile.header.headers[0].name, "Authorization"); + assert_eq!(barbfile.header.headers[0].value, "BLAH"); + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..816bebc --- /dev/null +++ b/src/main.rs @@ -0,0 +1,9 @@ +mod barbfile; + +use std::fs; +use ureq; + +fn main() { + let barbfile = fs::read_to_string("test.barb").expect("Failed to read file"); + ureq::get("https://api.met.no/weatherapi/tafmetar/1.0/tafmetar?icao=EGKK"); +} |