nu_protocol/config/
plugin_gc.rs1use super::prelude::*;
2use crate as nu_protocol;
3use std::collections::HashMap;
4
5#[derive(Clone, Debug, Default, IntoValue, PartialEq, Eq, Serialize, Deserialize)]
7pub struct PluginGcConfigs {
8 pub default: PluginGcConfig,
10 pub plugins: HashMap<String, PluginGcConfig>,
12}
13
14impl PluginGcConfigs {
15 pub fn get(&self, plugin_name: &str) -> &PluginGcConfig {
18 self.plugins.get(plugin_name).unwrap_or(&self.default)
19 }
20}
21
22impl UpdateFromValue for PluginGcConfigs {
23 fn update<'a>(
24 &mut self,
25 value: &'a Value,
26 path: &mut ConfigPath<'a>,
27 errors: &mut ConfigErrors,
28 ) {
29 let Value::Record { val: record, .. } = value else {
30 errors.type_mismatch(path, Type::record(), value);
31 return;
32 };
33
34 for (col, val) in record.iter() {
35 let path = &mut path.push(col);
36 match col.as_str() {
37 "default" => self.default.update(val, path, errors),
38 "plugins" => self.plugins.update(val, path, errors),
39 _ => errors.unknown_option(path, val),
40 }
41 }
42 }
43}
44
45#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
47pub struct PluginGcConfig {
48 pub enabled: bool,
50 pub stop_after: i64,
52}
53
54impl Default for PluginGcConfig {
55 fn default() -> Self {
56 PluginGcConfig {
57 enabled: true,
58 stop_after: 10_000_000_000, }
60 }
61}
62
63impl IntoValue for PluginGcConfig {
64 fn into_value(self, span: Span) -> Value {
65 record! {
66 "enabled" => self.enabled.into_value(span),
67 "stop_after" => Value::duration(self.stop_after, span),
68 }
69 .into_value(span)
70 }
71}
72
73impl UpdateFromValue for PluginGcConfig {
74 fn update<'a>(
75 &mut self,
76 value: &'a Value,
77 path: &mut ConfigPath<'a>,
78 errors: &mut ConfigErrors,
79 ) {
80 let Value::Record { val: record, .. } = value else {
81 errors.type_mismatch(path, Type::record(), value);
82 return;
83 };
84
85 for (col, val) in record.iter() {
86 let path = &mut path.push(col);
87 match col.as_str() {
88 "enabled" => self.enabled.update(val, path, errors),
89 "stop_after" => {
90 if let Ok(duration) = val.as_duration() {
91 if duration >= 0 {
92 self.stop_after = duration;
93 } else {
94 errors.invalid_value(path, "a non-negative duration", val);
95 }
96 } else {
97 errors.type_mismatch(path, Type::Duration, val);
98 }
99 }
100 _ => errors.unknown_option(path, val),
101 }
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use crate::{Config, Span, record};
110
111 fn test_pair() -> (PluginGcConfigs, Value) {
112 (
113 PluginGcConfigs {
114 default: PluginGcConfig {
115 enabled: true,
116 stop_after: 30_000_000_000,
117 },
118 plugins: [(
119 "my_plugin".to_owned(),
120 PluginGcConfig {
121 enabled: false,
122 stop_after: 0,
123 },
124 )]
125 .into_iter()
126 .collect(),
127 },
128 Value::test_record(record! {
129 "default" => Value::test_record(record! {
130 "enabled" => Value::test_bool(true),
131 "stop_after" => Value::test_duration(30_000_000_000),
132 }),
133 "plugins" => Value::test_record(record! {
134 "my_plugin" => Value::test_record(record! {
135 "enabled" => Value::test_bool(false),
136 "stop_after" => Value::test_duration(0),
137 }),
138 }),
139 }),
140 )
141 }
142
143 #[test]
144 fn update() {
145 let (expected, input) = test_pair();
146 let config = Config::default();
147 let mut errors = ConfigErrors::new(&config);
148 let mut result = PluginGcConfigs::default();
149 result.update(&input, &mut ConfigPath::new(), &mut errors);
150 assert!(errors.is_empty(), "errors: {errors:#?}");
151 assert_eq!(expected, result);
152 }
153
154 #[test]
155 fn reconstruct() {
156 let (input, expected) = test_pair();
157 assert_eq!(expected, input.into_value(Span::test_data()));
158 }
159}