Last active
January 6, 2024 23:28
-
-
Save passcod/9148782657f3f40df75ff85b8dd77c2a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! Parse ini with deku | |
//! | |
//! You need this https://github.com/sharksforarms/deku/pull/387 branch of deku for it to work. | |
//! | |
//! See https://twitter.com/passcod/status/1743186223940935754 | |
use deku::prelude::*; | |
use std::fs::read_to_string; | |
fn main() { | |
tracing_subscriber::fmt::init(); | |
let source = read_to_string("super/python-http.service").unwrap(); | |
let (_rest, unit) = Unit::from_bytes((source.as_bytes(), 0)).unwrap(); | |
println!("{:#?}", unit); | |
} | |
#[deku_derive(DekuRead)] | |
#[derive(Debug)] | |
struct Unit { | |
#[deku(temp, until = "|b: &u8| *b == b'['")] | |
head_ws: Vec<u8>, | |
#[deku(read_all)] | |
sections: Vec<Section>, | |
} | |
#[deku_derive(DekuRead)] | |
#[derive(Debug)] | |
struct Section { | |
#[deku( | |
until = "|b: &u8| *b == b']'", | |
map = "|bytes: Vec<u8>| -> Result<String, DekuError> { deku_bytes_to_string(bytes).map(clean(']')).map(normalise_case) }" | |
)] | |
name: String, | |
#[deku( | |
until = "|p: &MaybeProperty| p.property.is_none()", | |
map = "MaybeProperty::finalise_all" | |
)] | |
properties: Vec<Property>, | |
} | |
impl Section { | |
fn last(&self) -> bool { | |
todo!() | |
} | |
} | |
#[deku_derive(DekuRead)] | |
#[derive(Debug)] | |
struct MaybeProperty { | |
#[deku(until = "|b: &u8| *b != b'\\n'")] | |
ws: VecTilEnd<u8>, | |
#[deku(cond = "ws.0.last().map_or(false, |c| c != &b'[')")] | |
property: Option<Property>, | |
} | |
impl MaybeProperty { | |
fn finalise(self) -> Option<Property> { | |
if let Some(mut property) = self.property { | |
if let Some(c) = self.ws.0.last().map(|b| *b as char) { | |
property.key.insert(0, c); | |
} | |
Some(property) | |
} else { | |
None | |
} | |
} | |
fn finalise_all(mpv: Vec<MaybeProperty>) -> Result<Vec<Property>, DekuError> { | |
Ok(mpv.into_iter().filter_map(Self::finalise).collect()) | |
} | |
} | |
#[deku_derive(DekuRead)] | |
#[derive(Debug)] | |
struct Property { | |
#[deku(until = "|b: &u8| *b == b'='", map = "cleaned_string('=')")] | |
key: String, | |
#[deku(until = "|b: &u8| *b == b'\\n'", map = "cleaned_string('\\n')")] | |
value: String, | |
} | |
fn cleaned_string(end: char) -> impl Fn(Vec<u8>) -> Result<String, DekuError> { | |
move |bytes: Vec<u8>| -> Result<String, DekuError> { | |
deku_bytes_to_string(bytes).map(clean(end)) | |
} | |
} | |
fn deku_bytes_to_string(bytes: Vec<u8>) -> Result<String, DekuError> { | |
String::from_utf8(bytes).map_err(|e| DekuError::Parse(format!("{e}"))) | |
} | |
fn clean(end: char) -> impl Fn(String) -> String { | |
move |bytes: String| -> String { | |
bytes | |
.trim_start() | |
.trim_end() | |
.trim_end_matches(end) | |
.to_string() | |
} | |
} | |
fn normalise_case(string: String) -> String { | |
let mut lower = string.to_lowercase(); | |
lower.replace_range(0..1, &string[0..1].to_uppercase()); | |
lower | |
} | |
#[derive(Debug)] | |
struct VecTilEnd<T>(Vec<T>); | |
impl<'a, T, Ctx, Predicate> DekuReader<'a, (deku::ctx::Limit<T, Predicate>, Ctx)> for VecTilEnd<T> | |
where | |
T: DekuReader<'a, Ctx>, | |
Ctx: Copy, | |
Predicate: FnMut(&T) -> bool, | |
{ | |
fn from_reader_with_ctx<R: std::io::Read>( | |
reader: &mut deku::reader::Reader<R>, | |
(limit, inner_ctx): (deku::ctx::Limit<T, Predicate>, Ctx), | |
) -> Result<Self, DekuError> | |
where | |
Self: Sized, | |
{ | |
let deku::ctx::Limit::Until(mut predicate, _) = limit else { | |
return Err(DekuError::Parse("`until` is required here".to_string())); | |
}; | |
let mut res = Vec::new(); | |
let start_read = reader.bits_read; | |
loop { | |
if reader.end() { | |
break; | |
} | |
let val = <T>::from_reader_with_ctx(reader, inner_ctx)?; | |
res.push(val); | |
if predicate(res.last().unwrap()) { | |
break; | |
} | |
} | |
Ok(Self(res)) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Unit] | |
Description=Python HTTP static file server | |
After=network.target | |
[Service] | |
ExecStart=/usr/bin/python3 -mhttp.server | |
[Install] | |
WantedBy=multi-user.target |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment