varsun/mswin.rs
1// -*- coding: utf-8 -*-
2// vi: set sts=4 ts=4 sw=4 et ft=rust:
3
4//! Provides MS-Windows style substition.
5//!
6//! MS-Winodws style substition is `%var%` format strings.
7//! You can see on COMMAND PROMPT (not PowerShell).
8
9/// Parse src and substitute found variables with result of `mapfn`.
10///
11/// # Examples
12///
13/// ```
14/// use varsun::mswin::substitute;
15///
16/// let src = "foo is %foo%.";
17/// let res = substitute(src, |name: &str| -> Option<String> {
18/// match name {
19/// "foo" => Some("FOO!!".to_string()),
20/// _ => None, // If None returns, variable replaces with "" (empty string).
21/// }
22/// });
23/// ```
24pub fn substitute<F>(src: &str, mapfn: F) -> String where F: Fn(&str) -> Option<String> {
25 let mut dst = String::new();
26 let mut chs = src.chars();
27
28 // Temporary variables.
29 let mut varname = String::new();
30 let mut started = false;
31
32 // Check each characters.
33 while let Some(ch) = chs.next() {
34 if ch == '%' {
35 if started {
36 // Reach end of varname section.
37
38 // Call mapping-function.
39 if let Some(val) = mapfn(varname.as_str()) {
40 // Push raw value.
41 dst.push_str(val.as_str());
42
43 // Leave varname section.
44 started = false;
45 } else {
46 // Push Back Variable.
47 dst.push('%');
48 dst.push_str(varname.as_str());
49 }
50
51 // Reset varname.
52 varname.clear();
53 } else {
54 // Enter varname section.
55 started = true;
56
57 // Continue to Next.
58 continue;
59 }
60 } else {
61 if started {
62 // Part of varname.
63 varname.push(ch);
64 } else {
65 // Part of text.
66 dst.push(ch);
67 }
68 }
69 }
70
71 // Push Back vaname if cursor placed in varname section yet.
72 if started {
73 dst.push('%');
74 dst.push_str(varname.as_str());
75
76 // Reset
77 varname.clear();
78 }
79
80 return dst;
81}
82
83/// Substitute environment variable by Windows format.
84pub fn substenvar(src: &str) -> String {
85 return self::substitute(src, super::envar);
86}
87
88#[cfg(test)]
89mod tests {
90 fn mapfn(name: &str) -> Option<String> {
91 match name {
92 "foo" => Some("foo!!".to_string()),
93 "bar" => Some("!bar!".to_string()),
94 "baz" => Some("%baz%".to_string()),
95 _ => Some("( ・ω・)?".to_string()),
96 }
97 }
98
99 #[test]
100 fn substitute_basic() {
101 assert_eq!("foo!!", super::substitute("%foo%", mapfn));
102 assert_eq!("!bar!", super::substitute("%bar%", mapfn));
103 assert_eq!("%baz%", super::substitute("%baz%", mapfn));
104 assert_eq!("foo is foo!!", super::substitute("foo is %foo%", mapfn));
105 assert_eq!("!bar! not ( ・ω・)?", super::substitute("%bar% not %foobar%", mapfn));
106 assert_eq!("foo!!!bar!%baz%", super::substitute("%foo%%bar%%baz%", mapfn));
107 }
108
109 //#[bench]
110 //fn substitute_bench(b: &mut Bencher) {
111 // b.iter(|| super::substitute("%foo%%bar%%baz%", mapfn));
112 //}
113
114 #[test]
115 fn substenvar_basic() {
116 ::std::env::set_var("FOO", "foo, foo!");
117 ::std::env::set_var("BAR", "foobar");
118
119 assert_eq!("foo, foo!", super::substenvar("%FOO%"));
120 assert_eq!("foobar says 'foo, foo!'", super::substenvar("%BAR% says '%FOO%'"));
121 assert_eq!("%BAZ%", super::substenvar("%BAZ%"));
122 }
123
124}