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