1use crate::{error::BindError, source::SourceRegistry};
2
3pub trait Bindable {
28 fn bind_secrets(&mut self, registry: &SourceRegistry) -> Result<(), Vec<BindError>>;
33}
34
35pub fn bind_all<T: Bindable>(
39 target: &mut T,
40 registry: &SourceRegistry,
41) -> Result<(), Vec<BindError>> {
42 target.bind_secrets(registry)
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use crate::{Secret, SourceRegistry};
49
50 struct Config {
51 key_a: Secret<String>,
52 key_b: Secret<String>,
53 }
54
55 impl Bindable for Config {
56 fn bind_secrets(&mut self, registry: &SourceRegistry) -> Result<(), Vec<BindError>> {
57 let mut errors = Vec::new();
58 if let Err(e) = self.key_a.bind(registry) {
59 errors.push(e);
60 }
61 if let Err(e) = self.key_b.bind(registry) {
62 errors.push(e);
63 }
64 if errors.is_empty() {
65 Ok(())
66 } else {
67 Err(errors)
68 }
69 }
70 }
71
72 #[test]
73 fn bind_all_populates_both_secrets() {
74 unsafe {
75 std::env::set_var("BINDABLE_TEST_A", "alpha");
76 std::env::set_var("BINDABLE_TEST_B", "beta");
77 }
78
79 let mut config = Config {
80 key_a: Secret::new("urn:secrets-rs:env:BINDABLE_TEST_A").unwrap(),
81 key_b: Secret::new("urn:secrets-rs:env:BINDABLE_TEST_B").unwrap(),
82 };
83
84 let registry = SourceRegistry::new();
85 bind_all(&mut config, ®istry).unwrap();
86
87 assert_eq!(config.key_a.value().unwrap(), "alpha");
88 assert_eq!(config.key_b.value().unwrap(), "beta");
89
90 unsafe {
91 std::env::remove_var("BINDABLE_TEST_A");
92 std::env::remove_var("BINDABLE_TEST_B");
93 }
94 }
95
96 #[test]
97 fn bind_all_collects_all_errors() {
98 unsafe {
99 std::env::remove_var("BINDABLE_MISSING_A");
100 std::env::remove_var("BINDABLE_MISSING_B");
101 }
102
103 let mut config = Config {
104 key_a: Secret::new("urn:secrets-rs:env:BINDABLE_MISSING_A").unwrap(),
105 key_b: Secret::new("urn:secrets-rs:env:BINDABLE_MISSING_B").unwrap(),
106 };
107
108 let registry = SourceRegistry::new();
109 let errors = bind_all(&mut config, ®istry).unwrap_err();
110 assert_eq!(errors.len(), 2);
111 }
112}