git.delta.rocks / fleet / refs/commits / f48f507511e2

difftreelog

feat preserve object field order

Yaroslav Bolyukin2021-09-18parent: #fb6d303.patch.diff

5 files changed

modifiedcrates/nixlike/Cargo.tomldiffbeforeafterboth
--- a/crates/nixlike/Cargo.toml
+++ b/crates/nixlike/Cargo.toml
@@ -8,6 +8,7 @@
 [dependencies]
 anyhow = "1.0.44"
 dprint-core = "0.46.2"
+linked-hash-map = "0.5.4"
 peg = "0.7.0"
 serde = "1.0.130"
 serde_json = "1.0.68"
modifiedcrates/nixlike/src/de_impl.rsdiffbeforeafterboth
--- a/crates/nixlike/src/de_impl.rs
+++ b/crates/nixlike/src/de_impl.rs
@@ -1,8 +1,6 @@
-use std::{
-	collections::BTreeMap,
-	convert::{TryFrom, TryInto},
-};
+use std::convert::{TryFrom, TryInto};
 
+use linked_hash_map::LinkedHashMap;
 use serde::{
 	de::{self, MapAccess, SeqAccess},
 	Deserializer,
@@ -11,11 +9,11 @@
 use crate::{Error, Value};
 
 struct ObjectAccess {
-	iter: std::collections::btree_map::IntoIter<String, Value>,
+	iter: linked_hash_map::IntoIter<String, Value>,
 	value: Option<Value>,
 }
 impl ObjectAccess {
-	fn new(v: BTreeMap<String, Value>) -> Self {
+	fn new(v: LinkedHashMap<String, Value>) -> Self {
 		Self {
 			iter: v.into_iter(),
 			value: None,
@@ -103,7 +101,7 @@
 			_ => Err(Error::Expected("array")),
 		}
 	}
-	fn parse_object(self) -> Result<BTreeMap<String, Value>, Error> {
+	fn parse_object(self) -> Result<LinkedHashMap<String, Value>, Error> {
 		match self {
 			Value::Object(s) => Ok(s),
 			_ => Err(Error::Expected("object")),
modifiedcrates/nixlike/src/lib.rsdiffbeforeafterboth
before · crates/nixlike/src/lib.rs
1use std::collections::BTreeMap;23use peg::str::LineCol;4use se_impl::MySerialize;5use serde::{Deserialize, Serialize};67mod de_impl;8mod se_impl;9mod to_string;1011#[derive(thiserror::Error, Debug)]12pub enum Error {13	#[error("bad number")]14	BadNumber,15	#[error("expected {0}")]16	Expected(&'static str),17	#[error("parse error")]18	ParseError(#[from] peg::error::ParseError<LineCol>),19	#[error("{0}")]20	Custom(String),21	#[error("io: {0}")]22	Io(#[from] std::io::Error),23	#[error("fmt: {0}")]24	Fmt(#[from] std::fmt::Error),25}2627#[derive(Debug)]28pub enum Value {29	Number(i64),30	String(String),31	Boolean(bool),32	Object(BTreeMap<String, Value>),33	Array(Vec<Value>),34	Null,35}3637peg::parser! {38pub grammar nixlike() for str {39	rule number() -> i6440		= quiet! { v:$(['0'..='9' | '+' | '-']+) {? v.parse().map_err(|_| "<number>")} } / expected!("<number>")41	rule string_char() -> &'input str42		= "\\\"" { "\"" }43		/ "\\\\" { "\\" }44		/ c:$([_]) { c }45	rule string() -> String46		= quiet! { "\"" v:(!"\"" c:string_char() {c})* "\"" { v.into_iter().collect() } } / expected!("<string>")47	rule boolean() -> bool48		= quiet! { "true" {true}49		/ "false" {false} } / expected!("<boolean>")50	rule indent() -> String51		= quiet! { s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-']+) { s.to_owned() } } / expected!("<identifier>")52	rule object() -> BTreeMap<String, Value>53		= "{" _54			e:(k:indent()++(_ "." _) _ "=" _ v:value() _ ";" _ {(k, v)})*55		"}" {?56			let mut out = BTreeMap::new();57			for (k, v) in e {58				let mut map = &mut out;59				for v in k.iter().take(k.len() - 1) {60					map = match map.entry(v.clone()).or_insert_with(|| Value::Object(Default::default())) {61						Value::Object(v) => v,62						_ => return Err("expected object"),63					}64				}6566				let key = k.into_iter().last().unwrap();67				if map.contains_key(&key) {68					return Err("can't override object");69				}70				map.insert(key, v);71			}72			Ok(out)73		}7475	rule array() -> Vec<Value>76		= "[" _ v:value()**_ _ "]" {v}7778	rule value() -> Value79		= o:object() { Value::Object(o) }80		/ a:array() { Value::Array(a) }81		/ s:string() { Value::String(s) }82		/ "null" { Value::Null }83		/ b:boolean() { Value::Boolean(b) }84		/ n:number() { Value::Number(n) }8586	pub rule root() -> Value87		= _ v:value() _ { v }8889	rule _()90		= ( quiet!{ [' ' | '\t' | '\n']+ }91		/ "#" (!['\n'] [_])* "\n" )*92}93}9495pub fn parse_str<'de, D: Deserialize<'de>>(s: &str) -> Result<D, Error> {96	let value = nixlike::root(s)?;97	D::deserialize(value)98}99100pub fn parse_value<'de, D: Deserialize<'de>>(value: Value) -> Result<D, Error> {101	D::deserialize(value)102}103104pub fn serialize_value_pretty(value: Value) -> String {105	to_string::write_nix(&value)106}107108pub fn serialize<S: Serialize>(value: S) -> Result<String, Error> {109	let value: Value = value.serialize(MySerialize)?;110	Ok(serialize_value_pretty(value))111}112113#[test]114fn test() {115	let v: serde_json::Value = parse_str(116		r#"117			{118				b.c = 2;119				b.d = "hello";120				c = {121					k = 123;122					p = 231;123					ll = [1 2 3 [] [[4 5 6]] ];124				};125			}126		"#,127	)128	.unwrap();129	let s: String = serialize(v).unwrap();130	println!("{}", s);131}
modifiedcrates/nixlike/src/se_impl.rsdiffbeforeafterboth
--- a/crates/nixlike/src/se_impl.rs
+++ b/crates/nixlike/src/se_impl.rs
@@ -1,5 +1,6 @@
-use std::{collections::BTreeMap, convert::TryInto};
+use std::convert::TryInto;
 
+use linked_hash_map::LinkedHashMap;
 use serde::{
 	ser::{
 		self, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTuple,
@@ -96,7 +97,7 @@
 	}
 }
 
-pub struct MySerializeMap(BTreeMap<String, Value>, Option<String>);
+pub struct MySerializeMap(LinkedHashMap<String, Value>, Option<String>);
 
 impl SerializeMap for MySerializeMap {
 	type Ok = Value;
@@ -127,7 +128,7 @@
 	}
 }
 
-pub struct MySerializeStruct(BTreeMap<String, Value>);
+pub struct MySerializeStruct(LinkedHashMap<String, Value>);
 
 impl SerializeStruct for MySerializeStruct {
 	type Ok = Value;
@@ -147,7 +148,7 @@
 	}
 }
 
-pub struct MySerializeStructVariant(String, BTreeMap<String, Value>);
+pub struct MySerializeStructVariant(String, LinkedHashMap<String, Value>);
 
 impl SerializeStructVariant for MySerializeStructVariant {
 	type Ok = Value;
@@ -336,7 +337,7 @@
 	}
 
 	fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
-		Ok(MySerializeMap(BTreeMap::new(), None))
+		Ok(MySerializeMap(LinkedHashMap::new(), None))
 	}
 
 	fn serialize_struct(
@@ -344,7 +345,7 @@
 		_name: &'static str,
 		_len: usize,
 	) -> Result<Self::SerializeStruct, Self::Error> {
-		Ok(MySerializeStruct(BTreeMap::new()))
+		Ok(MySerializeStruct(LinkedHashMap::new()))
 	}
 
 	fn serialize_struct_variant(
@@ -356,7 +357,7 @@
 	) -> Result<Self::SerializeStructVariant, Self::Error> {
 		Ok(MySerializeStructVariant(
 			variant.to_owned(),
-			BTreeMap::new(),
+			LinkedHashMap::new(),
 		))
 	}
 }
modifiedcrates/nixlike/src/to_string.rsdiffbeforeafterboth
--- a/crates/nixlike/src/to_string.rs
+++ b/crates/nixlike/src/to_string.rs
@@ -41,7 +41,7 @@
 				out.push_signal(Signal::StartIndent);
 				out.push_condition(conditions::if_true_or(
 					"array start",
-					is_multiple_lines.clone(),
+					is_multiple_lines,
 					Signal::NewLine.into(),
 					Signal::SpaceOrNewLine.into(),
 				));
@@ -49,7 +49,7 @@
 					write_nix_buf(item, out);
 					out.push_condition(conditions::if_true_or(
 						"element separator",
-						is_multiple_lines.clone(),
+						is_multiple_lines,
 						Signal::NewLine.into(),
 						Signal::SpaceOrNewLine.into(),
 					));
@@ -73,7 +73,7 @@
 				out.push_signal(Signal::StartIndent);
 				out.push_condition(conditions::if_true_or(
 					"object start",
-					is_multiple_lines.clone(),
+					is_multiple_lines,
 					Signal::NewLine.into(),
 					Signal::SpaceOrNewLine.into(),
 				));
@@ -81,7 +81,7 @@
 					write_nix_obj_key_buf(k, v, out);
 					out.push_condition(conditions::if_true_or(
 						"element separator",
-						is_multiple_lines.clone(),
+						is_multiple_lines,
 						Signal::NewLine.into(),
 						Signal::SpaceOrNewLine.into(),
 					));