From 8482b7fea09cc2f25de837c2791e8beb403c2bb1 Mon Sep 17 00:00:00 2001 From: bluepython508 Date: Sat, 9 Dec 2023 22:27:53 +0000 Subject: [PATCH] Nested params --- example-tmpl/abc | 2 +- src/main.rs | 3 +-- src/manifest.rs | 56 +++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/example-tmpl/abc b/example-tmpl/abc index 694d149..12f66b0 100644 --- a/example-tmpl/abc +++ b/example-tmpl/abc @@ -1 +1 @@ -abc 123 {{ name }} +abc 123 {{ name }} {{ nested.param }} diff --git a/src/main.rs b/src/main.rs index 1c21e24..74aece9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -61,8 +61,7 @@ fn run( "Expected {} to be empty or not exist", destination.display() ); - // let destination = destination.canonicalize()?; - let params = Params(params.into_iter().collect()); + let params = Params::from_kv(params)?; context::Context::load(template, params)?.generate(destination)?; diff --git a/src/manifest.rs b/src/manifest.rs index 9f22829..a9e330a 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -1,7 +1,7 @@ -use eyre::Result; +use eyre::{bail, Result}; use serde::{Deserialize, Serialize}; -use tracing::instrument; use std::{collections::HashMap, convert::Infallible, path::PathBuf, str::FromStr}; +use tracing::instrument; #[derive(Debug, Clone, PartialEq, Deserialize)] pub struct Manifest { @@ -34,7 +34,7 @@ impl Source { Self::Path(relative) if relative.is_relative() => match self { Self::Path(root) => Self::Path(root.join(relative)), }, - other => other.clone() + other => other.clone(), } } @@ -48,7 +48,7 @@ impl Source { #[instrument] pub fn load(&self) -> Result> { match self { - Self::Path(path) => Ok(std::fs::read(path)?) + Self::Path(path) => Ok(std::fs::read(path)?), } } } @@ -89,7 +89,8 @@ impl Transform { } #[derive(Debug, Serialize, Deserialize, Default, Clone, PartialEq)] -pub struct Params(pub HashMap); +#[serde(transparent)] +pub struct Params(toml::Table); impl Params { pub fn load_user() -> Result { @@ -98,8 +99,47 @@ impl Params { )?)) } - pub fn merge(mut self, other: Self) -> Self { - self.0.extend(other.0); - self + pub fn from_kv(it: impl IntoIterator) -> Result { + it.into_iter() + .map(|(k, v)| { + let toml::Value::Table(val) = k + .split('.') + .rev() + .fold(toml::Value::String(v), |v, k| { + toml::Value::Table(toml::Table::from_iter([(k.to_owned(), v)])) + }) + else { + bail!("Key must not be empty") + }; + Ok(Self(val)) + }) + .try_fold(Self::default(), |acc, param| Ok(acc.merge(param?))) + } + + pub fn merge(self, other: Self) -> Self { + fn merge(v1: &mut toml::Value, v2: toml::Value) { + use toml::Value::*; + match (v1, v2) { + (Table(t1), Table(t2)) => { + for (k, v) in t2 { + match t1.entry(k) { + toml::map::Entry::Vacant(e) => { + e.insert(v); + } + toml::map::Entry::Occupied(e) => { + merge(e.into_mut(), v); + } + } + } + } + (v1, v2) => { + *v1 = v2; + } + } + } + let mut lhs = toml::Value::Table(self.0); + merge(&mut lhs, toml::Value::Table(other.0)); + let toml::Value::Table(table) = lhs else { unreachable!() }; + Self(table) } }