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

difftreelog

feat preserve object field order

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

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
--- a/crates/nixlike/src/lib.rs
+++ b/crates/nixlike/src/lib.rs
@@ -1,5 +1,4 @@
-use std::collections::BTreeMap;
-
+use linked_hash_map::LinkedHashMap;
 use peg::str::LineCol;
 use se_impl::MySerialize;
 use serde::{Deserialize, Serialize};
@@ -29,7 +28,7 @@
 	Number(i64),
 	String(String),
 	Boolean(bool),
-	Object(BTreeMap<String, Value>),
+	Object(LinkedHashMap<String, Value>),
 	Array(Vec<Value>),
 	Null,
 }
@@ -49,11 +48,11 @@
 		/ "false" {false} } / expected!("<boolean>")
 	rule indent() -> String
 		= quiet! { s:$(['a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '-']+) { s.to_owned() } } / expected!("<identifier>")
-	rule object() -> BTreeMap<String, Value>
+	rule object() -> LinkedHashMap<String, Value>
 		= "{" _
 			e:(k:indent()++(_ "." _) _ "=" _ v:value() _ ";" _ {(k, v)})*
 		"}" {?
-			let mut out = BTreeMap::new();
+			let mut out = LinkedHashMap::new();
 			for (k, v) in e {
 				let mut map = &mut out;
 				for v in k.iter().take(k.len() - 1) {
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
before · crates/nixlike/src/to_string.rs
1use crate::Value;2use dprint_core::formatting::{3	condition_resolvers, conditions, format, ConditionResolverContext, Info, PrintItems,4	PrintOptions, Signal,5};67fn write_nix_obj_key_buf(k: &str, v: &Value, out: &mut PrintItems) {8	out.push_str(k);9	match v {10		Value::Object(o) if o.len() == 1 => {11			let (k, v) = o.iter().next().unwrap();1213			out.push_str(".");14			write_nix_obj_key_buf(k, v, out);15		}16		v => {17			out.push_str(" = ");18			write_nix_buf(v, out);19			out.push_str(";");20		}21	}22}2324fn write_nix_buf(value: &Value, out: &mut PrintItems) {25	match value {26		Value::Null => out.push_str("null"),27		Value::Boolean(v) => out.push_str(if *v { "true" } else { "false" }),28		Value::Number(n) => out.push_str(&format!("{}", n)),29		Value::String(s) => out.push_str(&format!("{:?}", s)),30		Value::Array(a) => {31			if a.is_empty() {32				out.push_str("[ ]");33			} else {34				let start_info = Info::new("start");35				let end_info = Info::new("end");36				let is_multiple_lines = move |ctx: &mut ConditionResolverContext| {37					condition_resolvers::is_multiple_lines(ctx, &start_info, &end_info)38				};39				out.push_str("[");40				out.push_info(start_info);41				out.push_signal(Signal::StartIndent);42				out.push_condition(conditions::if_true_or(43					"array start",44					is_multiple_lines.clone(),45					Signal::NewLine.into(),46					Signal::SpaceOrNewLine.into(),47				));48				for item in a {49					write_nix_buf(item, out);50					out.push_condition(conditions::if_true_or(51						"element separator",52						is_multiple_lines.clone(),53						Signal::NewLine.into(),54						Signal::SpaceOrNewLine.into(),55					));56				}57				out.push_signal(Signal::FinishIndent);58				out.push_info(end_info);59				out.push_str("]");60			}61		}62		Value::Object(obj) => {63			if obj.is_empty() {64				out.push_str("{ }")65			} else {66				let start_info = Info::new("start");67				let end_info = Info::new("end");68				let is_multiple_lines = move |ctx: &mut ConditionResolverContext| {69					condition_resolvers::is_multiple_lines(ctx, &start_info, &end_info)70				};71				out.push_str("{");72				out.push_info(start_info);73				out.push_signal(Signal::StartIndent);74				out.push_condition(conditions::if_true_or(75					"object start",76					is_multiple_lines.clone(),77					Signal::NewLine.into(),78					Signal::SpaceOrNewLine.into(),79				));80				for (k, v) in obj {81					write_nix_obj_key_buf(k, v, out);82					out.push_condition(conditions::if_true_or(83						"element separator",84						is_multiple_lines.clone(),85						Signal::NewLine.into(),86						Signal::SpaceOrNewLine.into(),87					));88				}89				out.push_signal(Signal::FinishIndent);90				out.push_info(end_info);91				out.push_str("}");92			}93		}94	};95}9697pub fn write_nix(value: &Value) -> String {98	format(99		|| {100			let mut items = PrintItems::new();101			write_nix_buf(value, &mut items);102			items103		},104		PrintOptions {105			max_width: 120,106			use_tabs: false,107			indent_width: 2,108			new_line_text: "\n",109		},110	)111}