Repository: quartiq/stabilizer (language: rust)

Issue:
serial settings `list` should skip repeating default if equal
`/dual_iir/iir_ch/0/0: {"ba":[1.0,0.0,0.0,0.0,0.0],"u":0.0,"min":-32767.0,"max":32767.0} [default: {"ba":[1.0,0.0,0.0,0.0,0.0],"u":0.0,"min":-32767.0,"max":32767.0}]`

In the case where they are default, just say

`/dual_iir/iir_ch/0/0: {"ba":[1.0,0.0,0.0,0.0,0.0],"u":0.0,"min":-32767.0,"max":32767.0} [default]`



Discussion / hints:
I took a look at this yesterday because I was thinking the same. The main issue with implementation is that we only have a single copy in memory at a time (i.e. either the default version, or the current value. We can't compare them because as soon as we're done with one,  we erase it to format the next.
Maybe some PartialEq implementation could help, but we don't know the concrete type of the settings in `serial-settings`, so we are operating with the JSON-formatted version
It's a nice-to-have.
Maybe just split the serialize buffer for this?
Or hash each after serialization.

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index d58973172..0f20c7a00 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -706,9 +706,9 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.17"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
 dependencies = [
  "autocfg",
  "libm",
@@ -1059,6 +1059,7 @@ dependencies = [
  "heapless 0.8.0",
  "menu",
  "miniconf",
+ "yafnv",
 ]
 
 [[package]]
@@ -1401,3 +1402,12 @@ checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
 dependencies = [
  "vcell",
 ]
+
+[[package]]
+name = "yafnv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "804f6944df20b02a525b3cb607bcd90b43b6ef77c8943958781190847a052b70"
+dependencies = [
+ "num-traits",
+]
diff --git a/serial-settings/Cargo.toml b/serial-settings/Cargo.toml
index a88ac82a3..1219fb906 100644
--- a/serial-settings/Cargo.toml
+++ b/serial-settings/Cargo.toml
@@ -10,3 +10,4 @@ miniconf = "0.9"
 menu = {version = "0.4", features = ["echo"]}
 heapless = "0.8"
 embedded-io = "0.6"
+yafnv = "0.1"
diff --git a/serial-settings/src/lib.rs b/serial-settings/src/lib.rs
index 3f3b262f5..81a585b65 100644
--- a/serial-settings/src/lib.rs
+++ b/serial-settings/src/lib.rs
@@ -49,6 +49,7 @@
 #![no_std]
 
 use core::fmt::Write;
+use core::hash::Hasher;
 use embedded_io::{Read, ReadReady};
 use miniconf::{JsonCoreSlash, TreeKey};
 
@@ -122,7 +123,7 @@ impl<'a, P: Platform<Y>, const Y: usize> Context<'a, P, Y> {
             match path {
                 Err(e) => writeln!(context, "Failed to get path: {e}"),
                 Ok(path) => {
-                    match context
+                    let value = match context
                         .platform
                         .settings()
                         .get_json(&path, context.buffer)
@@ -132,26 +133,52 @@ impl<'a, P: Platform<Y>, const Y: usize> Context<'a, P, Y> {
                                 .unwrap();
                             continue;
                         }
-                        Ok(len) => write!(
+                        Ok(len) => core::str::from_utf8(&context.buffer[..len])
+                            .unwrap(),
+                    };
+
+                    write!(
+                        &mut context.platform.interface_mut(),
+                        "{path}: {value}"
+                    )
+                    .unwrap();
+
+                    let value_hash = {
+                        let mut hasher = yafnv::Fnv1aHasher::default();
+                        hasher.write(value.as_bytes());
+                        hasher.finish()
+                    };
+
+                    let default_value = match defaults
+                        .get_json(&path, context.buffer)
+                    {
+                        Err(e) => {
+                            writeln!(
+                                context,
+                                "[default serialization error: {e}]"
+                            )
+                            .unwrap();
+                            continue;
+                        }
+                        Ok(len) => core::str::from_utf8(&context.buffer[..len])
+                            .unwrap(),
+                    };
+
+                    let default_hash = {
+                        let mut hasher = yafnv::Fnv1aHasher::default();
+                        hasher.write(default_value.as_bytes());
+                        hasher.finish()
+                    };
+                    if default_hash != value_hash {
+                        writeln!(
                             &mut context.platform.interface_mut(),
-                            "{path}: {}",
-                            core::str::from_utf8(&context.buffer[..len])
-                                .unwrap()
+                            " [default: {default_value}]"
                         )
-                        .unwrap(),
-                    }
-
-                    match defaults.get_json(&path, context.buffer) {
-                        Err(e) => writeln!(
-                            context,
-                            "[default serialization error: {e}]"
-                        ),
-                        Ok(len) => writeln!(
+                    } else {
+                        writeln!(
                             &mut context.platform.interface_mut(),
-                            " [default: {}]",
-                            core::str::from_utf8(&context.buffer[..len])
-                                .unwrap()
-                        ),
+                            " [default]"
+                        )
                     }
                 }
             }


Test patch: