aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-29 03:34:41 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-29 03:34:41 +0800
commitba15b7c06468cb6c52c8d2a53419fd83f9ebcb8b (patch)
treecdaa1c71585d10dd73945cefe95f2c25f27924ed /src
parentff70307869a547b13850d1eec3f72e8ca3bca265 (diff)
refactor: promote project to workspace with macros sub-crate
Diffstat (limited to 'src')
-rw-r--r--src/deprecated.rs45
-rw-r--r--src/expand.rs212
-rw-r--r--src/lib.rs58
-rw-r--r--src/template.rs54
-rw-r--r--src/test.rs187
5 files changed, 0 insertions, 556 deletions
diff --git a/src/deprecated.rs b/src/deprecated.rs
deleted file mode 100644
index b218969..0000000
--- a/src/deprecated.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#[macro_export]
-macro_rules! tmpl_param {
- ($template:ident, $($key:ident = $value:expr),* $(,)?) => {{
- $(
- $template.insert_param(stringify!($key).to_string(), $value.to_string());
- )*
- }};
-}
-
-#[macro_export]
-macro_rules! tmpl {
- ($template:ident, $($name:ident {
- $($key:ident = $value:expr),* $(,)?
- }),* $(,)?) => {{
- $(
- let $name = $template.add_impl(stringify!($name).to_string());
- $(
- $name.push({
- let mut params = std::collections::HashMap::new();
- params.insert(stringify!($key).to_string(), $value.to_string());
- params
- });
- )*
- )*
- }};
-
- // Old syntax
- ($template:ident += {
- $($name:ident {
- $(($($key:ident = $value:expr),* $(,)?)),*
- $(,)?
- }),*
- }) => {{
- $(
- let $name = $template.add_impl(stringify!($name).to_string());
- $(
- $name.push({
- let mut params = std::collections::HashMap::new();
- $(params.insert(stringify!($key).to_string(), $value.to_string());)*
- params
- });
- )*
- )*
- }};
-}
diff --git a/src/expand.rs b/src/expand.rs
deleted file mode 100644
index b609113..0000000
--- a/src/expand.rs
+++ /dev/null
@@ -1,212 +0,0 @@
-use std::collections::HashMap;
-
-use just_fmt::snake_case;
-
-use crate::template::Template;
-
-const DISPLAY_BLOCK_BEGIN: &str = "??? >>> ";
-const DISPLAY_BLOCK_END: &str = "??? <<<";
-
-const IMPL_AREA_BEGIN: &str = "@@@ >>> ";
-const IMPL_AREA_END: &str = "@@@ <<<";
-
-const IMPL_BEGIN: &str = ">>>>>>>>>>";
-
-const PARAM_BEGIN: &str = "<<<";
-const PARAM_BEND: &str = ">>>";
-
-impl Template {
- pub fn expand(mut self) -> Option<String> {
- // Extract template text
- let expanded = std::mem::take(&mut self.template_str);
-
- let (expanded, impl_areas) = read_impl_areas(expanded)?;
- let expanded = apply_impls(&self, expanded, impl_areas)?;
- let expanded = apply_display_blocks(&self.params, expanded);
- let expanded = apply_param(&self, expanded)?;
- Some(expanded.trim().to_string())
- }
-}
-
-/// Read all ImplAreas (HashMap<Name, Codes>)
-fn read_impl_areas(content: String) -> Option<(String, HashMap<String, String>)> {
- let mut striped_content = String::new();
- let mut impl_areas: HashMap<String, String> = HashMap::new();
-
- let mut current_area_name = String::default();
- let mut current_area_codes: Vec<String> = Vec::new();
-
- for line in content.split("\n") {
- let trimmed_line = line.trim();
-
- // Implementation block end
- if trimmed_line.starts_with(IMPL_AREA_END) {
- // If the current ImplArea name length is less than 1, it means no block is being matched,
- // so matching fails, exit early
- if current_area_name.is_empty() {
- return None;
- }
-
- // Submit Impl Area
- let name = std::mem::take(&mut current_area_name);
- impl_areas.insert(name, current_area_codes.join("\n"));
- current_area_codes.clear();
- continue;
- }
-
- // Implementation block start
- if trimmed_line.starts_with(IMPL_AREA_BEGIN) {
- // If the current ImplArea name length is greater than 0, it means we are already inside a block,
- // since nesting is not allowed, matching fails, exit early
- if !current_area_name.is_empty() {
- return None;
- }
-
- // Get a snake_case name
- let snake_name = snake_case!(line.trim_start_matches(IMPL_AREA_BEGIN).trim());
- current_area_name = snake_name;
-
- // Continue to next line
- continue;
- }
-
- // During implementation block
- if !current_area_name.is_empty() {
- // Add to current block code
- current_area_codes.push(line.to_string());
- continue;
- } else {
- // Add to remaining content
- striped_content += "\n";
- striped_content += line;
- }
- }
-
- Some((striped_content, impl_areas))
-}
-
-/// Apply Template parameters to implementation block areas
-fn apply_impls(
- template: &Template,
- content: String,
- impl_areas: HashMap<String, String>,
-) -> Option<String> {
- let mut applied_content = String::new();
-
- let mut impled_areas: HashMap<String, Vec<String>> = HashMap::new();
- for (impl_area_name, impl_area_template) in impl_areas {
- // Get user-provided parameters
- let impl_items = template.impl_params.get(&impl_area_name);
-
- // No parameters, return early
- let Some(impl_items) = impl_items else {
- impled_areas.insert(impl_area_name, Vec::new());
- continue;
- };
-
- let mut impled_area_code_applied = Vec::new();
-
- // Split items
- for item in impl_items {
- // Get base template
- let mut applied = impl_area_template.clone();
-
- // Merge global params with arm-specific params for display block check
- let mut display_params = template.params.clone();
- for (k, v) in item {
- display_params.insert(k.clone(), v.clone());
- }
- applied = apply_display_blocks(&display_params, applied);
-
- // Extract parameters
- for (param_name, param_value) in item {
- // Apply parameter
- applied = applied.replace(
- &format!("{}{}{}", PARAM_BEGIN, param_name, PARAM_BEND),
- param_value,
- );
- }
-
- // Add applied template
- impled_area_code_applied.push(applied);
- }
-
- impled_areas.insert(impl_area_name, impled_area_code_applied);
- }
-
- for line in content.split("\n") {
- let trimmed_line = line.trim();
-
- // Recognize implementation line
- if trimmed_line.starts_with(IMPL_BEGIN) {
- let impl_name = snake_case!(trimmed_line.trim_start_matches(IMPL_BEGIN).trim());
-
- // Try to get implementation code block
- let Some(impled_code) = impled_areas.get(&impl_name) else {
- continue;
- };
-
- if !impled_code.is_empty() {
- applied_content += "\n";
- applied_content += impled_code.join("\n").as_str();
- }
- } else {
- // Other content directly appended
- applied_content += "\n";
- applied_content += line;
- }
- }
-
- Some(applied_content)
-}
-
-/// Process display blocks (`??? >>> name` / `??? <<<`).
-///
-/// If `params` contains a key matching the block name, the block content is
-/// included (with markers removed). Otherwise the entire block is omitted.
-fn apply_display_blocks(params: &HashMap<String, String>, content: String) -> String {
- let mut result = String::new();
- let lines: Vec<&str> = content.split("\n").collect();
- let mut i = 0;
- let mut first = true;
-
- while i < lines.len() {
- let line = lines[i];
- let trimmed = line.trim();
-
- if trimmed.starts_with(DISPLAY_BLOCK_BEGIN) {
- let block_name = trimmed.trim_start_matches(DISPLAY_BLOCK_BEGIN).trim();
- let show = params.contains_key(block_name);
- i += 1;
-
- while i < lines.len() && !lines[i].trim().starts_with(DISPLAY_BLOCK_END) {
- if show {
- if !first {
- result += "\n";
- }
- result += lines[i];
- first = false;
- }
- i += 1;
- }
- } else if !trimmed.starts_with(DISPLAY_BLOCK_END) {
- if !first {
- result += "\n";
- }
- result += line;
- first = false;
- }
-
- i += 1;
- }
-
- result
-}
-
-fn apply_param(template: &Template, content: String) -> Option<String> {
- let mut content = content;
- for (k, v) in template.params.iter() {
- content = content.replace(&format!("{}{}{}", PARAM_BEGIN, k, PARAM_BEND), v);
- }
- Some(content)
-}
diff --git a/src/lib.rs b/src/lib.rs
deleted file mode 100644
index 7ff77f5..0000000
--- a/src/lib.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-//! Template struct for storing template strings and their parameters.
-//!
-//! The template supports two types of parameters:
-//! - Simple parameters: key-value pairs used to replace simple placeholders (`<<<key>>>` format) in the template.
-//! - Implementation parameters: for implementation blocks (`>>>>>>>>> block_name` and `@@@ >>> block_name` format),
-//! can contain multiple parameter sets, each corresponding to an implementation instance.
-//!
-//! # Examples
-//! ```
-//! use just_template::Template;
-//!
-//! let mut tmpl = Template::from("Hello, <<<name>>>!".to_string());
-//! tmpl.insert_param("name".to_string(), "World".to_string());
-//! assert_eq!(tmpl.to_string(), "Hello, World!");
-//! ```
-//!
-//! Using the `tmpl_param!` macro makes it easier to add simple parameters:
-//! ```
-//! use just_template::{Template, tmpl_param};
-//!
-//! let mut tmpl = Template::from("<<<a>>> + <<<b>>> = <<<c>>>".to_string());
-//! tmpl_param!(tmpl, a = 1, b = 2, c = 3);
-//! assert_eq!(tmpl.to_string(), "1 + 2 = 3");
-//! ```
-//!
-//! Using the `tmpl!` macro adds implementation block parameters:
-//! ```
-//! use just_template::{Template, tmpl};
-//!
-//! let mut tmpl = Template::from("
-//! >>>>>>>>>> arms
-//! @@@ >>> arms
-//! <<<crate_name>>> => Some(<<<crate_name>>>::exec(data, params).await),
-//! @@@ <<<
-//! ".trim().to_string());
-//! tmpl!(tmpl,
-//! arms {
-//! crate_name = "my",
-//! crate_name = "you",
-//! }
-//! );
-//! // Output the expanded template
-//! let expanded = tmpl.to_string();
-//! assert_eq!(expanded, "
-//! my => Some(my::exec(data, params).await),
-//! you => Some(you::exec(data, params).await),
-//! ".trim().to_string());
-//! ```
-mod template;
-pub use template::*; // Re-export template to just_template
-
-pub mod expand;
-
-#[cfg(test)]
-pub mod test;
-
-#[deprecated]
-pub mod deprecated;
diff --git a/src/template.rs b/src/template.rs
deleted file mode 100644
index e368917..0000000
--- a/src/template.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use std::collections::HashMap;
-
-#[derive(Default, Clone)]
-pub struct Template {
- pub(crate) template_str: String,
- pub(crate) params: HashMap<String, String>,
- pub(crate) impl_params: HashMap<String, Vec<HashMap<String, String>>>,
-}
-
-impl Template {
- /// Add a parameter
- pub fn insert_param(&mut self, name: String, value: String) {
- self.params.insert(name, value);
- }
-
- /// Add an implementation block and return a HashMap to set its parameters
- pub fn add_impl(&mut self, impl_name: String) -> &mut Vec<HashMap<String, String>> {
- self.impl_params.entry(impl_name).or_default()
- }
-}
-
-impl From<String> for Template {
- fn from(s: String) -> Self {
- Template {
- template_str: s,
- ..Default::default()
- }
- }
-}
-
-impl<'a> From<&'a str> for Template {
- fn from(s: &'a str) -> Self {
- Template {
- template_str: s.to_string(),
- ..Default::default()
- }
- }
-}
-
-impl<'a> From<std::borrow::Cow<'a, str>> for Template {
- fn from(s: std::borrow::Cow<'a, str>) -> Self {
- Template {
- template_str: s.into_owned(),
- ..Default::default()
- }
- }
-}
-
-impl std::fmt::Display for Template {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let cloned = self.clone();
- write!(f, "{}", cloned.expand().unwrap_or_default())
- }
-}
diff --git a/src/test.rs b/src/test.rs
deleted file mode 100644
index ca7b357..0000000
--- a/src/test.rs
+++ /dev/null
@@ -1,187 +0,0 @@
-use std::collections::HashMap;
-
-use crate::template::Template;
-
-#[test]
-fn basic_param() {
- let mut tmpl = Template::from("Hello, <<<name>>>!".to_string());
- tmpl.insert_param("name".to_string(), "World".to_string());
- assert_eq!(tmpl.expand().unwrap(), "Hello, World!");
-}
-
-#[test]
-fn multi_param() {
- let mut tmpl = Template::from("<<<a>>> + <<<b>>> = <<<c>>>".to_string());
- tmpl.insert_param("a".to_string(), "1".to_string());
- tmpl.insert_param("b".to_string(), "2".to_string());
- tmpl.insert_param("c".to_string(), "3".to_string());
- assert_eq!(tmpl.expand().unwrap(), "1 + 2 = 3");
-}
-
-#[test]
-fn impl_blocks() {
- let mut tmpl = Template::from(
- r#"
->>>>>>>>>> arms
-@@@ >>> arms
- "<<<crate_name>>>" => Some(<<<crate_name>>>::exec(data, params).await),
-@@@ <<<
-"#
- .trim()
- .to_string(),
- );
-
- let arms = tmpl.add_impl("arms".to_string());
- arms.push(HashMap::from([(
- "crate_name".to_string(),
- "my".to_string(),
- )]));
- arms.push(HashMap::from([(
- "crate_name".to_string(),
- "you".to_string(),
- )]));
-
- let expanded = tmpl.expand().unwrap();
- assert!(expanded.contains(r#""my" => Some(my::exec(data, params).await)"#));
- assert!(expanded.contains(r#""you" => Some(you::exec(data, params).await)"#));
-}
-
-#[test]
-fn display_block_global_hidden_by_default() {
- let tmpl = Template::from(
- r#"
-visible line
-??? >>> debug
- hidden line
-??? <<<
-visible end
-"#
- .trim()
- .to_string(),
- );
-
- let expanded = tmpl.expand().unwrap();
- assert!(expanded.contains("visible line"));
- assert!(expanded.contains("visible end"));
- assert!(!expanded.contains("hidden line"));
-}
-
-#[test]
-fn display_block_global_shown_via_param() {
- let mut tmpl = Template::from(
- r#"
-visible line
-??? >>> debug
- shown line
-??? <<<
-visible end
-"#
- .trim()
- .to_string(),
- );
-
- tmpl.insert_param("debug".to_string(), "".to_string());
-
- let expanded = tmpl.expand().unwrap();
- assert!(expanded.contains("visible line"));
- assert!(expanded.contains("visible end"));
- assert!(expanded.contains("shown line"));
-}
-
-#[test]
-fn display_block_inside_impl_area_hidden_by_default() {
- let mut tmpl = Template::from(
- r#"
->>>>>>>>>> arms
-@@@ >>> arms
- <<<crate_name>>> => exec,
-??? >>> extra
- <<<crate_name>>> => metrics,
-??? <<<
-@@@ <<<
-"#
- .trim()
- .to_string(),
- );
-
- let arms = tmpl.add_impl("arms".to_string());
- arms.push(HashMap::from([(
- "crate_name".to_string(),
- "my".to_string(),
- )]));
-
- let expanded = tmpl.expand().unwrap();
- assert!(expanded.contains(r#"my => exec"#));
- assert!(!expanded.contains(r#"my => metrics"#));
-}
-
-#[test]
-fn display_block_inside_impl_area_shown_by_global_param() {
- let mut tmpl = Template::from(
- r#"
->>>>>>>>>> arms
-@@@ >>> arms
- <<<crate_name>>> => exec,
-??? >>> extra
- <<<crate_name>>> => metrics,
-??? <<<
-@@@ <<<
-"#
- .trim()
- .to_string(),
- );
-
- // Enable via global param — shows for ALL arms
- tmpl.insert_param("extra".to_string(), "".to_string());
-
- let arms = tmpl.add_impl("arms".to_string());
- arms.push(HashMap::from([(
- "crate_name".to_string(),
- "my".to_string(),
- )]));
- arms.push(HashMap::from([(
- "crate_name".to_string(),
- "you".to_string(),
- )]));
-
- let expanded = tmpl.expand().unwrap();
- assert!(expanded.contains(r#"my => exec"#));
- assert!(expanded.contains(r#"my => metrics"#));
- assert!(expanded.contains(r#"you => exec"#));
- assert!(expanded.contains(r#"you => metrics"#));
-}
-
-#[test]
-fn display_block_inside_impl_area_shown_by_arm_param() {
- let mut tmpl = Template::from(
- r#"
->>>>>>>>>> arms
-@@@ >>> arms
- <<<crate_name>>> => exec,
-??? >>> extra
- <<<crate_name>>> => metrics,
-??? <<<
-@@@ <<<
-"#
- .trim()
- .to_string(),
- );
-
- let arms = tmpl.add_impl("arms".to_string());
- // Arm 1: no "extra" → hidden
- arms.push(HashMap::from([(
- "crate_name".to_string(),
- "my".to_string(),
- )]));
- // Arm 2: has "extra" → shown for this arm only
- arms.push(HashMap::from([
- ("crate_name".to_string(), "you".to_string()),
- ("extra".to_string(), "".to_string()),
- ]));
-
- let expanded = tmpl.expand().unwrap();
- assert!(expanded.contains(r#"my => exec"#));
- assert!(!expanded.contains(r#"my => metrics"#));
- assert!(expanded.contains(r#"you => exec"#));
- assert!(expanded.contains(r#"you => metrics"#));
-}