git.delta.rocks / jrsonnet / refs/commits / 2c5a4bd2d3da

difftreelog

source

crates/nixlike/src/lib.rs3.5 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;1213pub use to_string::escape_string;1415#[derive(thiserror::Error, Debug)]16pub enum Error {17	#[error("bad number")]18	BadNumber,19	#[error("expected {0}")]20	Expected(&'static str),21	#[error("parse error")]22	ParseError(#[from] peg::error::ParseError<LineCol>),23	#[error("{0}")]24	Custom(String),25	#[error("io: {0}")]26	Io(#[from] std::io::Error),27	#[error("fmt: {0}")]28	Fmt(#[from] std::fmt::Error),29}3031#[derive(Debug)]32pub enum Value {33	Number(i64),34	String(String),35	Boolean(bool),36	Object(LinkedHashMap<String, Value>),37	Array(Vec<Value>),38	Null,39}4041peg::parser! {42pub grammar nixlike() for str {43	rule number() -> i6444		= quiet! { v:$(['0'..='9' | '+' | '-']+) {? v.parse().map_err(|_| "<number>")} } / expected!("<number>")45	rule string_char() -> &'input str46		= "\\\"" { "\"" }47		/ "\\\\" { "\\" }48		/ "\\n" { "\n" }49		/ "\\t" { "\t" }50		/ "\\r" { "\r" }51		/ "\\$" { "$" }52		/ c:$([_]) { c }53	rule string() -> String54		= quiet! { "\"" v:(!"\"" c:string_char() {c})* "\"" { v.into_iter().collect() } } / expected!("<string>")55	rule boolean() -> bool56		= quiet! { "true" {true}57		/ "false" {false} } / expected!("<boolean>")58	rule indent() -> String59		= quiet! {60			s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-']+) { s.to_owned() }61			/ "\"" s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-' | '.']+) "\"" { s.to_owned() }62		} / expected!("<identifier>")63	rule object() -> LinkedHashMap<String, Value>64		= "{" _65			e:(k:indent()++(_ "." _) _ "=" _ v:value() _ ";" _ {(k, v)})*66		"}" {?67			let mut out = LinkedHashMap::new();68			for (k, v) in e {69				let mut map = &mut out;70				for v in k.iter().take(k.len() - 1) {71					map = match map.entry(v.clone()).or_insert_with(|| Value::Object(Default::default())) {72						Value::Object(v) => v,73						_ => return Err("expected object"),74					}75				}7677				let key = k.into_iter().last().unwrap();78				if map.contains_key(&key) {79					return Err("can't override object");80				}81				map.insert(key, v);82			}83			Ok(out)84		}8586	rule array() -> Vec<Value>87		= "[" _ v:value()**_ _ "]" {v}8889	rule value() -> Value90		= o:object() { Value::Object(o) }91		/ a:array() { Value::Array(a) }92		/ s:string() { Value::String(s) }93		/ "null" { Value::Null }94		/ b:boolean() { Value::Boolean(b) }95		/ n:number() { Value::Number(n) }9697	pub rule root() -> Value98		= _ v:value() _ { v }99100	rule _()101		= ( quiet!{ [' ' | '\t' | '\n']+ }102		/ "#" (!['\n'] [_])* "\n" )*103}104}105106pub fn parse_str<'de, D: Deserialize<'de>>(s: &str) -> Result<D, Error> {107	let value = nixlike::root(s)?;108	D::deserialize(value)109}110111pub fn parse_value<'de, D: Deserialize<'de>>(value: Value) -> Result<D, Error> {112	D::deserialize(value)113}114115pub fn serialize_value_pretty(value: Value) -> String {116	to_string::write_nix(&value)117}118119pub fn serialize<S: Serialize>(value: S) -> Result<String, Error> {120	let value: Value = value.serialize(MySerialize)?;121	Ok(serialize_value_pretty(value))122}123124pub fn format_identifier(i: &str) -> String {125	let mut out = String::new();126	to_string::write_identifier(i, &mut out);127	out128}129130#[test]131fn test() {132	assert_eq!(serialize("Hello\nworld").unwrap(), "\"Hello\\nworld\"\n");133}134pub fn format_nix(value: &String) -> String {135	let (_, out) = alejandra::format::in_memory("".to_owned(), value.to_owned());136	out137}