1use std::{
2 cell::RefCell,
3 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
4 hash::Hash,
5 net::{Ipv4Addr, SocketAddr},
6 num::{
7 NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroU16, NonZeroU32, NonZeroU64,
8 NonZeroU8, NonZeroUsize,
9 },
10 path::PathBuf,
11 time::Duration,
12};
13
14use indexmap::IndexMap;
15use serde_json::{Number, Value};
16use vector_config_common::{attributes::CustomAttribute, constants, validation::Validation};
17use vrl::value::KeyString;
18
19use crate::{
20 num::ConfigurableNumber,
21 schema::{
22 assert_string_schema_for_map, generate_array_schema, generate_bool_schema,
23 generate_map_schema, generate_number_schema, generate_optional_schema, generate_set_schema,
24 generate_string_schema, SchemaGenerator, SchemaObject,
25 },
26 str::ConfigurableString,
27 Configurable, GenerateError, Metadata, ToValue,
28};
29
30impl Configurable for () {
32 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
33 Err(GenerateError::InvalidType)
35 }
36}
37
38impl ToValue for () {
39 fn to_value(&self) -> Value {
40 Value::Null
41 }
42}
43
44impl<T> Configurable for Option<T>
46where
47 T: Configurable + ToValue + 'static,
48{
49 fn referenceable_name() -> Option<&'static str> {
50 match T::referenceable_name() {
51 None => None,
52 Some(_) => Some(std::any::type_name::<Self>()),
53 }
54 }
55
56 fn is_optional() -> bool {
57 true
58 }
59
60 fn metadata() -> Metadata {
61 Metadata::with_transparent(true)
62 }
63
64 fn validate_metadata(metadata: &Metadata) -> Result<(), GenerateError> {
65 let converted = metadata.convert();
67 T::validate_metadata(&converted)
68 }
69
70 fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
71 generate_optional_schema(&T::as_configurable_ref(), gen)
72 }
73}
74
75impl<T: ToValue> ToValue for Option<T> {
76 fn to_value(&self) -> Value {
77 match self {
78 None => Value::Null,
79 Some(inner) => inner.to_value(),
80 }
81 }
82}
83
84impl Configurable for bool {
85 fn metadata() -> Metadata {
86 Metadata::with_transparent(true)
87 }
88
89 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
90 Ok(generate_bool_schema())
91 }
92}
93
94impl ToValue for bool {
95 fn to_value(&self) -> Value {
96 Value::Bool(*self)
97 }
98}
99
100impl Configurable for String {
102 fn metadata() -> Metadata {
103 Metadata::with_transparent(true)
104 }
105
106 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
107 Ok(generate_string_schema())
108 }
109}
110
111impl ToValue for String {
112 fn to_value(&self) -> Value {
113 Value::String(self.clone())
114 }
115}
116
117impl Configurable for KeyString {
118 fn metadata() -> Metadata {
119 Metadata::with_transparent(true)
120 }
121
122 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
123 Ok(generate_string_schema())
124 }
125}
126
127impl ToValue for KeyString {
128 fn to_value(&self) -> Value {
129 Value::String(self.clone().into())
130 }
131}
132
133impl Configurable for char {
134 fn metadata() -> Metadata {
135 let mut metadata = Metadata::with_transparent(true);
136 metadata.add_validation(Validation::Length {
137 minimum: Some(1),
138 maximum: Some(1),
139 });
140 metadata
141 }
142
143 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
144 Ok(generate_string_schema())
145 }
146}
147
148impl ToValue for char {
149 fn to_value(&self) -> Value {
150 Value::String(format!("{self}"))
151 }
152}
153
154macro_rules! impl_configurable_numeric {
156 ($ty:ty => $into:expr) => {
157 impl Configurable for $ty {
158 fn metadata() -> Metadata {
159 let mut metadata = Metadata::with_transparent(true);
160 let numeric_type = <Self as ConfigurableNumber>::class();
161 metadata.add_custom_attribute(CustomAttribute::kv(
162 constants::DOCS_META_NUMERIC_TYPE,
163 numeric_type,
164 ));
165
166 metadata
167 }
168
169 fn validate_metadata(metadata: &Metadata) -> Result<(), GenerateError> {
170 $crate::__ensure_numeric_validation_bounds::<Self>(metadata)
171 }
172
173 fn generate_schema(
174 _: &RefCell<SchemaGenerator>,
175 ) -> Result<SchemaObject, GenerateError> {
176 Ok(generate_number_schema::<Self>())
177 }
178 }
179
180 impl ToValue for $ty {
181 fn to_value(&self) -> Value {
182 let into = $into;
183 Value::Number(into(*self))
184 }
185 }
186 };
187}
188
189impl_configurable_numeric!(u8 => Into::into);
190impl_configurable_numeric!(u16 => Into::into);
191impl_configurable_numeric!(u32 => Into::into);
192impl_configurable_numeric!(u64 => Into::into);
193impl_configurable_numeric!(usize => Into::into);
194impl_configurable_numeric!(i8 => Into::into);
195impl_configurable_numeric!(i16 => Into::into);
196impl_configurable_numeric!(i32 => Into::into);
197impl_configurable_numeric!(i64 => Into::into);
198impl_configurable_numeric!(isize => Into::into);
199impl_configurable_numeric!(f32 => |v| Number::from_f64(v as f64).expect("Could not convert number to JSON"));
200impl_configurable_numeric!(f64 => |v| Number::from_f64(v).expect("Could not convert number to JSON"));
201impl_configurable_numeric!(NonZeroU8 => |v: NonZeroU8| v.get().into());
202impl_configurable_numeric!(NonZeroU16 => |v: NonZeroU16| v.get().into());
203impl_configurable_numeric!(NonZeroU32 => |v: NonZeroU32| v.get().into());
204impl_configurable_numeric!(NonZeroU64 => |v: NonZeroU64| v.get().into());
205impl_configurable_numeric!(NonZeroI8 => |v: NonZeroI8| v.get().into());
206impl_configurable_numeric!(NonZeroI16 => |v: NonZeroI16| v.get().into());
207impl_configurable_numeric!(NonZeroI32 => |v: NonZeroI32| v.get().into());
208impl_configurable_numeric!(NonZeroI64 => |v: NonZeroI64| v.get().into());
209impl_configurable_numeric!(NonZeroUsize => |v: NonZeroUsize| v.get().into());
210
211impl<T> Configurable for Vec<T>
213where
214 T: Configurable + ToValue + 'static,
215{
216 fn metadata() -> Metadata {
217 T::metadata().convert()
218 }
219
220 fn validate_metadata(metadata: &Metadata) -> Result<(), GenerateError> {
221 let converted = metadata.convert();
222 T::validate_metadata(&converted)
223 }
224
225 fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
226 generate_array_schema(&T::as_configurable_ref(), gen)
227 }
228}
229
230impl<T: ToValue> ToValue for Vec<T> {
231 fn to_value(&self) -> Value {
232 Value::Array(self.iter().map(ToValue::to_value).collect())
233 }
234}
235
236impl<K, V> Configurable for BTreeMap<K, V>
237where
238 K: ConfigurableString + Ord + ToValue + 'static,
239 V: Configurable + ToValue + 'static,
240{
241 fn is_optional() -> bool {
242 true
245 }
246
247 fn metadata() -> Metadata {
248 Metadata::with_transparent(true)
249 }
250
251 fn validate_metadata(metadata: &Metadata) -> Result<(), GenerateError> {
252 let converted = metadata.convert();
253 V::validate_metadata(&converted)
254 }
255
256 fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
257 assert_string_schema_for_map(
259 &K::as_configurable_ref(),
260 gen,
261 std::any::type_name::<Self>(),
262 )?;
263
264 generate_map_schema(&V::as_configurable_ref(), gen)
265 }
266}
267
268impl<K, V> ToValue for BTreeMap<K, V>
269where
270 K: ToString,
271 V: ToValue,
272{
273 fn to_value(&self) -> Value {
274 Value::Object(
275 self.iter()
276 .map(|(k, v)| (k.to_string(), v.to_value()))
277 .collect(),
278 )
279 }
280}
281
282impl<V> Configurable for BTreeSet<V>
283where
284 V: Configurable + ToValue + Eq + Hash + 'static,
285{
286 fn metadata() -> Metadata {
287 Metadata::with_transparent(true)
288 }
289
290 fn validate_metadata(metadata: &Metadata) -> Result<(), GenerateError> {
291 let converted = metadata.convert();
292 V::validate_metadata(&converted)
293 }
294
295 fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
296 generate_set_schema(&V::as_configurable_ref(), gen)
297 }
298}
299
300impl<V: ToValue> ToValue for BTreeSet<V> {
301 fn to_value(&self) -> Value {
302 Value::Array(self.iter().map(ToValue::to_value).collect())
303 }
304}
305
306impl<K, V> Configurable for HashMap<K, V>
307where
308 K: ConfigurableString + ToValue + Hash + Eq + 'static,
309 V: Configurable + ToValue + 'static,
310{
311 fn is_optional() -> bool {
312 true
315 }
316
317 fn metadata() -> Metadata {
318 Metadata::with_transparent(true)
319 }
320
321 fn validate_metadata(metadata: &Metadata) -> Result<(), GenerateError> {
322 let converted = metadata.convert();
323 V::validate_metadata(&converted)
324 }
325
326 fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
327 assert_string_schema_for_map(
329 &K::as_configurable_ref(),
330 gen,
331 std::any::type_name::<Self>(),
332 )?;
333
334 generate_map_schema(&V::as_configurable_ref(), gen)
335 }
336}
337
338impl<K, V> ToValue for HashMap<K, V>
339where
340 K: ToString,
341 V: ToValue,
342{
343 fn to_value(&self) -> Value {
344 Value::Object(
345 self.iter()
346 .map(|(k, v)| (k.to_string(), v.to_value()))
347 .collect(),
348 )
349 }
350}
351
352impl<V> Configurable for HashSet<V>
353where
354 V: Configurable + ToValue + Eq + Hash + 'static,
355{
356 fn metadata() -> Metadata {
357 Metadata::with_transparent(true)
358 }
359
360 fn validate_metadata(metadata: &Metadata) -> Result<(), GenerateError> {
361 let converted = metadata.convert();
362 V::validate_metadata(&converted)
363 }
364
365 fn generate_schema(gen: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
366 generate_set_schema(&V::as_configurable_ref(), gen)
367 }
368}
369
370impl<V> ToValue for HashSet<V>
371where
372 V: ToValue,
373{
374 fn to_value(&self) -> Value {
375 Value::Array(self.iter().map(ToValue::to_value).collect())
376 }
377}
378
379impl Configurable for SocketAddr {
381 fn referenceable_name() -> Option<&'static str> {
382 Some("stdlib::SocketAddr")
383 }
384
385 fn metadata() -> Metadata {
386 let mut metadata = Metadata::default();
387 metadata.set_description("An internet socket address, either IPv4 or IPv6.");
388 metadata
389 }
390
391 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
392 Ok(generate_string_schema())
396 }
397}
398
399impl ToValue for SocketAddr {
400 fn to_value(&self) -> Value {
401 Value::String(self.to_string())
402 }
403}
404
405impl Configurable for Ipv4Addr {
406 fn referenceable_name() -> Option<&'static str> {
407 Some("stdlib::Ipv4Addr")
408 }
409
410 fn metadata() -> Metadata {
411 let mut metadata = Metadata::default();
412 metadata.set_description("An IPv4 address.");
413 metadata
414 }
415
416 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
417 Ok(generate_string_schema())
421 }
422}
423
424impl ToValue for Ipv4Addr {
425 fn to_value(&self) -> Value {
426 Value::String(self.to_string())
427 }
428}
429
430impl Configurable for PathBuf {
431 fn referenceable_name() -> Option<&'static str> {
432 Some("stdlib::PathBuf")
433 }
434
435 fn metadata() -> Metadata {
436 let mut metadata = Metadata::default();
437 metadata.set_description("A file path.");
438
439 const PATH_REGEX: &str = r#"(\/.*|[a-zA-Z]:\\(?:([^<>:"\/\\|?*]*[^<>:"\/\\|?*.]\\|..\\)*([^<>:"\/\\|?*]*[^<>:"\/\\|?*.]\\?|..\\))?)"#;
444 metadata.add_validation(Validation::Pattern(PATH_REGEX.to_string()));
445
446 metadata
447 }
448
449 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
450 Ok(generate_string_schema())
451 }
452}
453
454impl ToValue for PathBuf {
455 fn to_value(&self) -> Value {
456 Value::String(self.display().to_string())
457 }
458}
459
460impl Configurable for Duration {
462 fn referenceable_name() -> Option<&'static str> {
463 Some("stdlib::Duration")
464 }
465
466 fn metadata() -> Metadata {
467 let mut metadata = Metadata::default();
468 metadata.set_description("An duration of time.");
469 metadata
470 }
471
472 fn generate_schema(_: &RefCell<SchemaGenerator>) -> Result<SchemaObject, GenerateError> {
473 let mut properties = IndexMap::default();
474 properties.insert("secs".into(), generate_number_schema::<u64>());
475 properties.insert("nsecs".into(), generate_number_schema::<u32>());
476
477 let mut required = BTreeSet::default();
478 required.insert("secs".into());
479 required.insert("nsecs".into());
480
481 Ok(crate::schema::generate_struct_schema(
482 properties, required, None,
483 ))
484 }
485}
486
487impl ToValue for Duration {
488 fn to_value(&self) -> Value {
489 serde_json::to_value(self).expect("Could not convert duration to JSON")
490 }
491}