Skip to content

Commit 6ea8aa6

Browse files
committed
functora-cfg: configurable key in hash_map, functora-tagged: blanket Deref and Hash impls
1 parent f89204d commit 6ea8aa6

File tree

3 files changed

+51
-18
lines changed

3 files changed

+51
-18
lines changed

rust/functora-cfg/src/lib.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use clap::{Args, FromArgMatches, Subcommand};
33
pub use config::ConfigError;
44
use config::{Config, Environment, File, Value};
55
use serde::{Deserialize, Serialize, de::DeserializeOwned};
6+
use std::hash::Hash;
67
use std::{collections::HashMap, path::Path};
78
use toml::Value as TomlValue;
89

@@ -97,7 +98,7 @@ fn toml_to_config(toml: TomlValue) -> Value {
9798
TomlValue::Table(kv) => Value::from(
9899
kv.into_iter()
99100
.map(|(k, v)| (k, toml_to_config(v)))
100-
.collect::<config::Map<String, Value>>(),
101+
.collect::<config::Map<_, Value>>(),
101102
),
102103
}
103104
}
@@ -126,22 +127,26 @@ where
126127
T: Args,
127128
U: Subcommand,
128129
{
129-
pub fn vec(self, f: fn(U) -> ReClap<T, U>) -> Vec<T> {
130+
pub fn vec(self, rec: fn(U) -> ReClap<T, U>) -> Vec<T> {
130131
let mut prev = vec![self.prev];
131132
if let Some(next) = self.next {
132-
prev.extend(f(*next).vec(f))
133+
prev.extend(rec(*next).vec(rec))
133134
}
134135
prev
135136
}
136137

137-
pub fn hash_map(
138+
pub fn hash_map<K, E>(
138139
self,
139-
f: fn(U) -> ReClap<T, U>,
140-
) -> HashMap<String, T> {
141-
self.vec(f)
140+
key: fn(usize) -> Result<K, E>,
141+
rec: fn(U) -> ReClap<T, U>,
142+
) -> Result<HashMap<K, T>, E>
143+
where
144+
K: Eq + Hash,
145+
{
146+
self.vec(rec)
142147
.into_iter()
143148
.enumerate()
144-
.map(|(k, v)| (k.to_string(), v))
149+
.map(|(k, v)| key(k).map(|k| (k, v)))
145150
.collect()
146151
}
147152
}

rust/functora-cfg/tests/integration.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,17 @@ struct Cfg {
2121
}
2222

2323
impl Cfg {
24-
pub fn new(cli: Cli<SubAccount>) -> Self {
24+
pub fn new(
25+
cli: Cli<SubAccount>,
26+
) -> Result<Self, ConfigError> {
2527
functora_cfg::Cfg {
2628
default: &Cli::def(),
2729
file_path: |cli| cli.toml.as_deref(),
2830
env_prefix: "FUNCTORA",
2931
command_line: &cli
30-
.fmap(|x| IdClap(x.hash_map())),
32+
.try_fmap(|kv| kv.hash_map().map(IdClap))?,
3133
}
3234
.eval()
33-
.unwrap()
3435
}
3536
}
3637

@@ -58,9 +59,15 @@ pub enum SubAccount {
5859
}
5960

6061
impl SubAccount {
61-
pub fn hash_map(self) -> HashMap<String, CliAccount> {
62+
pub fn hash_map(
63+
self,
64+
) -> Result<HashMap<String, CliAccount>, ConfigError>
65+
{
6266
let SubAccount::SubAccount(prev) = self;
63-
prev.hash_map(|SubAccount::SubAccount(next)| next)
67+
prev.hash_map(
68+
|k| Ok(k.to_string()),
69+
|SubAccount::SubAccount(next)| next,
70+
)
6471
}
6572
}
6673

@@ -136,7 +143,8 @@ impl Cli<IdClap<HashMap<String, CliAccount>>> {
136143
#[test]
137144
#[serial]
138145
fn defaults() {
139-
let lhs = Cfg::new(Cli::parse_from(["functora"]));
146+
let lhs =
147+
Cfg::new(Cli::parse_from(["functora"])).unwrap();
140148
let rhs = Cfg {
141149
host: "127.0.0.1".into(),
142150
port: 8080,
@@ -170,7 +178,8 @@ fn file_override() {
170178
"functora",
171179
"--toml",
172180
&file.path().to_string_lossy(),
173-
]));
181+
]))
182+
.unwrap();
174183
let rhs = Cfg {
175184
host: "192.168.1.100".into(),
176185
port: 8080,
@@ -218,7 +227,8 @@ fn env_override() {
218227
],
219228
|| {
220229
let lhs =
221-
Cfg::new(Cli::parse_from(["functora"]));
230+
Cfg::new(Cli::parse_from(["functora"]))
231+
.unwrap();
222232
let rhs = Cfg {
223233
host: "10.0.0.1".into(),
224234
port: 7070,
@@ -260,7 +270,8 @@ fn cli_override() {
260270
"pure",
261271
"--tags",
262272
"geek",
263-
]));
273+
]))
274+
.unwrap();
264275
let rhs = Cfg {
265276
host: "127.0.0.1".into(),
266277
port: 6060,
@@ -331,7 +342,8 @@ fn layered_override() {
331342
"vip",
332343
"--tags",
333344
"beta",
334-
]));
345+
]))
346+
.unwrap();
335347

336348
let rhs = Cfg {
337349
host: "10.10.10.10".into(),

rust/functora-tagged/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
use derive_more::Display;
33
use std::error::Error;
44
use std::fmt::{Debug, Display};
5+
use std::hash::{Hash, Hasher};
56
use std::marker::PhantomData;
7+
use std::ops::Deref;
68
use std::str::FromStr;
79

810
#[derive(Debug)]
@@ -66,6 +68,20 @@ impl<Rep: Display, Tag> Display for Tagged<Rep, Tag> {
6668
}
6769
}
6870

71+
impl<Rep: Hash, Tag> Hash for Tagged<Rep, Tag> {
72+
fn hash<H: Hasher>(&self, state: &mut H) {
73+
self.rep().hash(state);
74+
}
75+
}
76+
77+
impl<Rep, Tag> Deref for Tagged<Rep, Tag> {
78+
type Target = Rep;
79+
80+
fn deref(&self) -> &Self::Target {
81+
self.rep()
82+
}
83+
}
84+
6985
#[derive(Debug, Display)]
7086
pub enum ParseError<Rep, Tag>
7187
where

0 commit comments

Comments
 (0)