git.delta.rocks / jrsonnet / refs/commits / 8d4a7a16f575

difftreelog

source

crates/nixlike/src/lib.rs3.2 KiBsourcehistory
1//! Serialization/deserialization for nix subset usable for static configurations2//! Serialized results from this library are readable by both this library and standard nix tools34use linked_hash_map::LinkedHashMap;5use peg::str::LineCol;6use se_impl::MySerialize;7use serde::{Deserialize, Serialize};89mod de_impl;10mod se_impl;11mod to_string;1213#[derive(thiserror::Error, Debug)]14pub enum Error {15	#[error("bad number")]16	BadNumber,17	#[error("expected {0}")]18	Expected(&'static str),19	#[error("parse error")]20	ParseError(#[from] peg::error::ParseError<LineCol>),21	#[error("{0}")]22	Custom(String),23	#[error("io: {0}")]24	Io(#[from] std::io::Error),25	#[error("fmt: {0}")]26	Fmt(#[from] std::fmt::Error),27}2829#[derive(Debug)]30pub enum Value {31	Number(i64),32	String(String),33	Boolean(bool),34	Object(LinkedHashMap<String, Value>),35	Array(Vec<Value>),36	Null,37}3839peg::parser! {40pub grammar nixlike() for str {41	rule number() -> i6442		= quiet! { v:$(['0'..='9' | '+' | '-']+) {? v.parse().map_err(|_| "<number>")} } / expected!("<number>")43	rule string_char() -> &'input str44		= "\\\"" { "\"" }45		/ "\\\\" { "\\" }46		/ "\\n" { "\n" }47		/ "\\t" { "\t" }48		/ "\\r" { "\r" }49		/ "\\$" { "$" }50		/ c:$([_]) { c }51	rule string() -> String52		= quiet! { "\"" v:(!"\"" c:string_char() {c})* "\"" { v.into_iter().collect() } } / expected!("<string>")53	rule boolean() -> bool54		= quiet! { "true" {true}55		/ "false" {false} } / expected!("<boolean>")56	rule indent() -> String57		= quiet! {58			s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-']+) { s.to_owned() }59			/ "\"" s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '.']+) "\"" { s.to_owned() }60		} / expected!("<identifier>")61	rule object() -> LinkedHashMap<String, Value>62		= "{" _63			e:(k:indent()++(_ "." _) _ "=" _ v:value() _ ";" _ {(k, v)})*64		"}" {?65			let mut out = LinkedHashMap::new();66			for (k, v) in e {67				let mut map = &mut out;68				for v in k.iter().take(k.len() - 1) {69					map = match map.entry(v.clone()).or_insert_with(|| Value::Object(Default::default())) {70						Value::Object(v) => v,71						_ => return Err("expected object"),72					}73				}7475				let key = k.into_iter().last().unwrap();76				if map.contains_key(&key) {77					return Err("can't override object");78				}79				map.insert(key, v);80			}81			Ok(out)82		}8384	rule array() -> Vec<Value>85		= "[" _ v:value()**_ _ "]" {v}8687	rule value() -> Value88		= o:object() { Value::Object(o) }89		/ a:array() { Value::Array(a) }90		/ s:string() { Value::String(s) }91		/ "null" { Value::Null }92		/ b:boolean() { Value::Boolean(b) }93		/ n:number() { Value::Number(n) }9495	pub rule root() -> Value96		= _ v:value() _ { v }9798	rule _()99		= ( quiet!{ [' ' | '\t' | '\n']+ }100		/ "#" (!['\n'] [_])* "\n" )*101}102}103104pub fn parse_str<'de, D: Deserialize<'de>>(s: &str) -> Result<D, Error> {105	let value = nixlike::root(s)?;106	D::deserialize(value)107}108109pub fn parse_value<'de, D: Deserialize<'de>>(value: Value) -> Result<D, Error> {110	D::deserialize(value)111}112113pub fn serialize_value_pretty(value: Value) -> String {114	to_string::write_nix(&value)115}116117pub fn serialize<S: Serialize>(value: S) -> Result<String, Error> {118	let value: Value = value.serialize(MySerialize)?;119	Ok(serialize_value_pretty(value))120}121122#[test]123fn test() {124	assert_eq!(serialize("Hello\nworld").unwrap(), "\"Hello\\nworld\"");125}