1use serde::ser::{SerializeSeq, Serializer};
136use serde::Serialize;
137
138pub mod config_type {
139 #[derive(Clone, Debug)]
140 pub struct Integer;
141 #[derive(Clone, Debug)]
142 pub struct DefaultInteger;
143 #[derive(Clone, Debug)]
144 pub struct IntegerArray;
145 #[derive(Clone, Debug)]
146 pub struct DefaultIntegerArray;
147 #[derive(Clone, Debug)]
148 pub struct String;
149 #[derive(Clone, Debug)]
150 pub struct DefaultString;
151 #[derive(Clone, Debug)]
152 pub struct StringArray;
153 #[derive(Clone, Debug)]
154 pub struct DefaultStringArray;
155 #[derive(Clone, Debug)]
156 pub struct Boolean;
157 #[derive(Clone, Debug)]
158 pub struct DefaultBoolean;
159 #[derive(Clone, Debug)]
160 pub struct Flag;
161}
162
163pub type IntegerConfigOption<'a> = ConfigOption<'a, config_type::Integer>;
165pub type IntegerArrayConfigOption<'a> = ConfigOption<'a, config_type::IntegerArray>;
167pub type StringConfigOption<'a> = ConfigOption<'a, config_type::String>;
169pub type StringArrayConfigOption<'a> = ConfigOption<'a, config_type::StringArray>;
171pub type BooleanConfigOption<'a> = ConfigOption<'a, config_type::Boolean>;
173pub type DefaultIntegerConfigOption<'a> = ConfigOption<'a, config_type::DefaultInteger>;
175pub type DefaultIntegerArrayConfigOption<'a> = ConfigOption<'a, config_type::DefaultIntegerArray>;
177pub type DefaultStringConfigOption<'a> = ConfigOption<'a, config_type::DefaultString>;
179pub type DefaultStringArrayConfigOption<'a> = ConfigOption<'a, config_type::DefaultStringArray>;
181pub type DefaultBooleanConfigOption<'a> = ConfigOption<'a, config_type::DefaultBoolean>;
183pub type FlagConfigOption<'a> = ConfigOption<'a, config_type::Flag>;
185
186pub trait OptionType<'a> {
187 type OutputValue;
188 type DefaultValue;
189
190 fn convert_default(value: &Self::DefaultValue) -> Option<Value>;
191
192 fn from_value(value: &Option<Value>) -> Self::OutputValue;
193
194 fn get_value_type() -> ValueType;
195}
196
197impl<'a> OptionType<'a> for config_type::DefaultString {
198 type OutputValue = String;
199 type DefaultValue = &'a str;
200
201 fn convert_default(value: &Self::DefaultValue) -> Option<Value> {
202 Some(Value::String(value.to_string()))
203 }
204
205 fn from_value(value: &Option<Value>) -> Self::OutputValue {
206 match value {
207 Some(Value::String(s)) => s.to_string(),
208 _ => panic!("Type mismatch. Expected string but found {:?}", value),
209 }
210 }
211
212 fn get_value_type() -> ValueType {
213 ValueType::String
214 }
215}
216
217impl<'a> OptionType<'a> for config_type::DefaultStringArray {
218 type OutputValue = Vec<String>;
219 type DefaultValue = &'a str;
220
221 fn convert_default(value: &Self::DefaultValue) -> Option<Value> {
222 Some(Value::String(value.to_string()))
223 }
224
225 fn from_value(value: &Option<Value>) -> Self::OutputValue {
226 match value {
227 Some(Value::StringArray(s)) => s.clone(),
228 _ => panic!("Type mismatch. Expected string-array but found {:?}", value),
229 }
230 }
231
232 fn get_value_type() -> ValueType {
233 ValueType::String
234 }
235}
236
237impl<'a> OptionType<'a> for config_type::DefaultInteger {
238 type OutputValue = i64;
239 type DefaultValue = i64;
240
241 fn convert_default(value: &Self::DefaultValue) -> Option<Value> {
242 Some(Value::Integer(*value))
243 }
244
245 fn from_value(value: &Option<Value>) -> Self::OutputValue {
246 match value {
247 Some(Value::Integer(i)) => *i,
248 _ => panic!("Type mismatch. Expected Integer but found {:?}", value),
249 }
250 }
251
252 fn get_value_type() -> ValueType {
253 ValueType::Integer
254 }
255}
256
257impl<'a> OptionType<'a> for config_type::DefaultIntegerArray {
258 type OutputValue = Vec<i64>;
259 type DefaultValue = i64;
260
261 fn convert_default(value: &Self::DefaultValue) -> Option<Value> {
262 Some(Value::Integer(*value))
263 }
264
265 fn from_value(value: &Option<Value>) -> Self::OutputValue {
266 match value {
267 Some(Value::IntegerArray(i)) => i.clone(),
268 _ => panic!(
269 "Type mismatch. Expected Integer-array but found {:?}",
270 value
271 ),
272 }
273 }
274
275 fn get_value_type() -> ValueType {
276 ValueType::Integer
277 }
278}
279
280impl<'a> OptionType<'a> for config_type::DefaultBoolean {
281 type OutputValue = bool;
282 type DefaultValue = bool;
283
284 fn convert_default(value: &bool) -> Option<Value> {
285 Some(Value::Boolean(*value))
286 }
287 fn from_value(value: &Option<Value>) -> Self::OutputValue {
288 match value {
289 Some(Value::Boolean(b)) => *b,
290 _ => panic!("Type mismatch. Expected Boolean but found {:?}", value),
291 }
292 }
293
294 fn get_value_type() -> ValueType {
295 ValueType::Boolean
296 }
297}
298
299impl<'a> OptionType<'a> for config_type::Flag {
300 type OutputValue = bool;
301 type DefaultValue = ();
302
303 fn convert_default(_value: &()) -> Option<Value> {
304 Some(Value::Boolean(false))
305 }
306
307 fn from_value(value: &Option<Value>) -> Self::OutputValue {
308 match value {
309 Some(Value::Boolean(b)) => *b,
310 _ => panic!("Type mismatch. Expected Boolean but found {:?}", value),
311 }
312 }
313
314 fn get_value_type() -> ValueType {
315 ValueType::Flag
316 }
317}
318
319impl<'a> OptionType<'a> for config_type::String {
320 type OutputValue = Option<String>;
321 type DefaultValue = ();
322
323 fn convert_default(_value: &()) -> Option<Value> {
324 None
325 }
326
327 fn from_value(value: &Option<Value>) -> Self::OutputValue {
328 match value {
329 Some(Value::String(s)) => Some(s.to_string()),
330 None => None,
331 _ => panic!(
332 "Type mismatch. Expected Option<string> but found {:?}",
333 value
334 ),
335 }
336 }
337
338 fn get_value_type() -> ValueType {
339 ValueType::String
340 }
341}
342
343impl<'a> OptionType<'a> for config_type::StringArray {
344 type OutputValue = Option<Vec<String>>;
345 type DefaultValue = ();
346
347 fn convert_default(_value: &()) -> Option<Value> {
348 None
349 }
350
351 fn from_value(value: &Option<Value>) -> Self::OutputValue {
352 match value {
353 Some(Value::StringArray(s)) => Some(s.clone()),
354 None => None,
355 _ => panic!(
356 "Type mismatch. Expected Option<Vec<String>> but found {:?}",
357 value
358 ),
359 }
360 }
361
362 fn get_value_type() -> ValueType {
363 ValueType::String
364 }
365}
366
367impl<'a> OptionType<'a> for config_type::Integer {
368 type OutputValue = Option<i64>;
369 type DefaultValue = ();
370
371 fn convert_default(_value: &()) -> Option<Value> {
372 None
373 }
374
375 fn from_value(value: &Option<Value>) -> Self::OutputValue {
376 match value {
377 Some(Value::Integer(i)) => Some(*i),
378 None => None,
379 _ => panic!(
380 "Type mismatch. Expected Option<Integer> but found {:?}",
381 value
382 ),
383 }
384 }
385
386 fn get_value_type() -> ValueType {
387 ValueType::Integer
388 }
389}
390
391impl<'a> OptionType<'a> for config_type::IntegerArray {
392 type OutputValue = Option<Vec<i64>>;
393 type DefaultValue = ();
394
395 fn convert_default(_value: &()) -> Option<Value> {
396 None
397 }
398
399 fn from_value(value: &Option<Value>) -> Self::OutputValue {
400 match value {
401 Some(Value::IntegerArray(i)) => Some(i.clone()),
402 None => None,
403 _ => panic!(
404 "Type mismatch. Expected Option<Vec<Integer>> but found {:?}",
405 value
406 ),
407 }
408 }
409
410 fn get_value_type() -> ValueType {
411 ValueType::Integer
412 }
413}
414
415impl<'a> OptionType<'a> for config_type::Boolean {
416 type OutputValue = Option<bool>;
417 type DefaultValue = ();
418
419 fn convert_default(_value: &()) -> Option<Value> {
420 None
421 }
422 fn from_value(value: &Option<Value>) -> Self::OutputValue {
423 match value {
424 Some(Value::Boolean(b)) => Some(*b),
425 None => None,
426 _ => panic!(
427 "Type mismatch. Expected Option<Boolean> but found {:?}",
428 value
429 ),
430 }
431 }
432
433 fn get_value_type() -> ValueType {
434 ValueType::Boolean
435 }
436}
437
438#[derive(Clone, Debug, Serialize)]
439pub enum ValueType {
440 #[serde(rename = "string")]
441 String,
442 #[serde(rename = "int")]
443 Integer,
444 #[serde(rename = "bool")]
445 Boolean,
446 #[serde(rename = "flag")]
447 Flag,
448}
449
450#[derive(Clone, Debug)]
451pub enum Value {
452 String(String),
453 Integer(i64),
454 Boolean(bool),
455 StringArray(Vec<String>),
456 IntegerArray(Vec<i64>),
457}
458
459impl Serialize for Value {
460 fn serialize<S>(&self, serializer: S) -> std::prelude::v1::Result<S::Ok, S::Error>
461 where
462 S: Serializer,
463 {
464 match self {
465 Value::String(s) => serializer.serialize_str(s),
466 Value::Integer(i) => serializer.serialize_i64(*i),
467 Value::Boolean(b) => serializer.serialize_bool(*b),
468 Value::StringArray(sa) => {
469 let mut seq = serializer.serialize_seq(Some(sa.len()))?;
470 for element in sa {
471 seq.serialize_element(element)?;
472 }
473 seq.end()
474 }
475 Value::IntegerArray(sa) => {
476 let mut seq = serializer.serialize_seq(Some(sa.len()))?;
477 for element in sa {
478 seq.serialize_element(element)?;
479 }
480 seq.end()
481 }
482 }
483 }
484}
485
486impl Value {
487 pub fn is_string(&self) -> bool {
492 self.as_str().is_some()
493 }
494
495 pub fn as_str(&self) -> Option<&str> {
498 match self {
499 Value::String(s) => Some(&s),
500 Value::Integer(_) => None,
501 Value::Boolean(_) => None,
502 Value::StringArray(_) => None,
503 Value::IntegerArray(_) => None,
504 }
505 }
506
507 pub fn is_i64(&self) -> bool {
513 self.as_i64().is_some()
514 }
515
516 pub fn as_i64(&self) -> Option<i64> {
519 match *self {
520 Value::Integer(n) => Some(n),
521 _ => None,
522 }
523 }
524
525 pub fn is_boolean(&self) -> bool {
530 self.as_bool().is_some()
531 }
532
533 pub fn as_bool(&self) -> Option<bool> {
536 match *self {
537 Value::Boolean(b) => Some(b),
538 _ => None,
539 }
540 }
541
542 pub fn is_str_arr(&self) -> bool {
547 self.as_str_arr().is_some()
548 }
549
550 pub fn as_str_arr(&self) -> Option<&Vec<String>> {
553 match self {
554 Value::StringArray(sa) => Some(sa),
555 _ => None,
556 }
557 }
558
559 pub fn is_i64_arr(&self) -> bool {
564 self.as_i64_arr().is_some()
565 }
566
567 pub fn as_i64_arr(&self) -> Option<&Vec<i64>> {
570 match self {
571 Value::IntegerArray(sa) => Some(sa),
572 _ => None,
573 }
574 }
575}
576
577#[derive(Clone, Debug)]
578pub struct ConfigOption<'a, V: OptionType<'a>> {
579 pub name: &'a str,
581 pub default: V::DefaultValue,
583 pub description: &'a str,
584 pub deprecated: bool,
585 pub dynamic: bool,
586 pub multi: bool,
587}
588
589impl<'a, V: OptionType<'a>> ConfigOption<'a, V> {
590 pub fn build(&self) -> UntypedConfigOption {
591 UntypedConfigOption {
592 name: self.name.to_string(),
593 value_type: V::get_value_type(),
594 default: <V as OptionType>::convert_default(&self.default),
595 description: self.description.to_string(),
596 deprecated: self.deprecated,
597 dynamic: self.dynamic,
598 multi: self.multi,
599 }
600 }
601}
602
603impl<'a> DefaultStringConfigOption<'a> {
604 pub const fn new_str_with_default(
605 name: &'a str,
606 default: &'a str,
607 description: &'a str,
608 ) -> Self {
609 Self {
610 name: name,
611 default: default,
612 description: description,
613 deprecated: false,
614 dynamic: false,
615 multi: false,
616 }
617 }
618 pub fn dynamic(mut self) -> Self {
619 self.dynamic = true;
620 self
621 }
622}
623
624impl<'a> StringConfigOption<'a> {
625 pub const fn new_str_no_default(name: &'a str, description: &'a str) -> Self {
626 Self {
627 name,
628 default: (),
629 description: description,
630 deprecated: false,
631 dynamic: false,
632 multi: false,
633 }
634 }
635 pub fn dynamic(mut self) -> Self {
636 self.dynamic = true;
637 self
638 }
639}
640
641impl<'a> DefaultStringArrayConfigOption<'a> {
642 pub const fn new_str_arr_with_default(
643 name: &'a str,
644 default: &'a str,
645 description: &'a str,
646 ) -> Self {
647 Self {
648 name,
649 default,
650 description,
651 deprecated: false,
652 dynamic: false,
653 multi: true,
654 }
655 }
656 pub fn dynamic(mut self) -> Self {
657 self.dynamic = true;
658 self
659 }
660}
661
662impl<'a> StringArrayConfigOption<'a> {
663 pub const fn new_str_arr_no_default(name: &'a str, description: &'a str) -> Self {
664 Self {
665 name,
666 default: (),
667 description,
668 deprecated: false,
669 dynamic: false,
670 multi: true,
671 }
672 }
673 pub fn dynamic(mut self) -> Self {
674 self.dynamic = true;
675 self
676 }
677}
678
679impl<'a> DefaultIntegerConfigOption<'a> {
680 pub const fn new_i64_with_default(name: &'a str, default: i64, description: &'a str) -> Self {
681 Self {
682 name: name,
683 default: default,
684 description: description,
685 deprecated: false,
686 dynamic: false,
687 multi: false,
688 }
689 }
690 pub fn dynamic(mut self) -> Self {
691 self.dynamic = true;
692 self
693 }
694}
695
696impl<'a> IntegerConfigOption<'a> {
697 pub const fn new_i64_no_default(name: &'a str, description: &'a str) -> Self {
698 Self {
699 name: name,
700 default: (),
701 description: description,
702 deprecated: false,
703 dynamic: false,
704 multi: false,
705 }
706 }
707 pub fn dynamic(mut self) -> Self {
708 self.dynamic = true;
709 self
710 }
711}
712
713impl<'a> DefaultIntegerArrayConfigOption<'a> {
714 pub const fn new_i64_arr_with_default(
715 name: &'a str,
716 default: i64,
717 description: &'a str,
718 ) -> Self {
719 Self {
720 name,
721 default,
722 description,
723 deprecated: false,
724 dynamic: false,
725 multi: true,
726 }
727 }
728 pub fn dynamic(mut self) -> Self {
729 self.dynamic = true;
730 self
731 }
732}
733
734impl<'a> IntegerArrayConfigOption<'a> {
735 pub const fn new_i64_arr_no_default(name: &'a str, description: &'a str) -> Self {
736 Self {
737 name,
738 default: (),
739 description,
740 deprecated: false,
741 dynamic: false,
742 multi: true,
743 }
744 }
745 pub fn dynamic(mut self) -> Self {
746 self.dynamic = true;
747 self
748 }
749}
750
751impl<'a> BooleanConfigOption<'a> {
752 pub const fn new_bool_no_default(name: &'a str, description: &'a str) -> Self {
753 Self {
754 name,
755 description,
756 default: (),
757 deprecated: false,
758 dynamic: false,
759 multi: false,
760 }
761 }
762 pub fn dynamic(mut self) -> Self {
763 self.dynamic = true;
764 self
765 }
766}
767
768impl<'a> DefaultBooleanConfigOption<'a> {
769 pub const fn new_bool_with_default(name: &'a str, default: bool, description: &'a str) -> Self {
770 Self {
771 name,
772 description,
773 default: default,
774 deprecated: false,
775 dynamic: false,
776 multi: false,
777 }
778 }
779 pub fn dynamic(mut self) -> Self {
780 self.dynamic = true;
781 self
782 }
783}
784
785impl<'a> FlagConfigOption<'a> {
786 pub const fn new_flag(name: &'a str, description: &'a str) -> Self {
787 Self {
788 name,
789 description,
790 default: (),
791 deprecated: false,
792 dynamic: false,
793 multi: false,
794 }
795 }
796 pub fn dynamic(mut self) -> Self {
797 self.dynamic = true;
798 self
799 }
800}
801
802fn is_false(b: &bool) -> bool {
803 *b == false
804}
805
806#[derive(Clone, Debug, Serialize)]
808pub struct UntypedConfigOption {
809 name: String,
810 #[serde(rename = "type")]
811 pub(crate) value_type: ValueType,
812 #[serde(skip_serializing_if = "Option::is_none")]
813 default: Option<Value>,
814 description: String,
815 #[serde(skip_serializing_if = "is_false")]
816 deprecated: bool,
817 dynamic: bool,
818 multi: bool,
819}
820
821impl UntypedConfigOption {
822 pub fn name(&self) -> &str {
823 &self.name
824 }
825 pub fn default(&self) -> &Option<Value> {
826 &self.default
827 }
828 pub fn dynamic(mut self) -> Self {
829 self.dynamic = true;
830 self
831 }
832}
833
834impl<'a, V> ConfigOption<'a, V>
835where
836 V: OptionType<'a>,
837{
838 pub fn name(&self) -> &str {
839 &self.name
840 }
841
842 pub fn description(&self) -> &str {
843 &self.description
844 }
845}
846
847#[cfg(test)]
848mod test {
849
850 use super::*;
851
852 #[test]
853 fn test_option_serialize() {
854 let tests = vec![
855 (
856 ConfigOption::new_str_with_default("name", "default", "description").build(),
857 json!({
858 "name": "name",
859 "description":"description",
860 "default": "default",
861 "type": "string",
862 "dynamic": false,
863 "multi": false,
864 }),
865 ),
866 (
867 ConfigOption::new_i64_with_default("name", 42, "description").build(),
868 json!({
869 "name": "name",
870 "description":"description",
871 "default": 42,
872 "type": "int",
873 "dynamic": false,
874 "multi": false,
875 }),
876 ),
877 (
878 {
879 ConfigOption::new_bool_with_default("name", true, "description")
880 .build()
881 .dynamic()
882 },
883 json!({
884 "name": "name",
885 "description":"description",
886 "default": true,
887 "type": "bool",
888 "dynamic": true,
889 "multi": false,
890 }),
891 ),
892 (
893 ConfigOption::new_flag("name", "description").build(),
894 json!({
895 "name" : "name",
896 "description": "description",
897 "type" : "flag",
898 "default" : false,
899 "dynamic": false,
900 "multi": false,
901 }),
902 ),
903 (
904 ConfigOption::new_str_arr_with_default("name", "Default1", "description").build(),
905 json!({
906 "name" : "name",
907 "description": "description",
908 "type" : "string",
909 "default" : "Default1",
910 "dynamic": false,
911 "multi": true,
912 }),
913 ),
914 (
915 ConfigOption::new_i64_arr_with_default("name", -46, "description").build(),
916 json!({
917 "name" : "name",
918 "description": "description",
919 "type" : "int",
920 "default" : -46,
921 "dynamic": false,
922 "multi": true,
923 }),
924 ),
925 ];
926
927 for (input, expected) in tests.iter() {
928 let res = serde_json::to_value(input).unwrap();
929 assert_eq!(&res, expected);
930 }
931 }
932
933 #[test]
934 fn const_config_option() {
935 const _: FlagConfigOption = ConfigOption::new_flag("flag-option", "A flag option");
939 const _: DefaultBooleanConfigOption =
940 ConfigOption::new_bool_with_default("bool-option", false, "A boolean option");
941 const _: BooleanConfigOption =
942 ConfigOption::new_bool_no_default("bool-option", "A boolean option");
943
944 const _: IntegerConfigOption =
945 ConfigOption::new_i64_no_default("integer-option", "A flag option");
946 const _: DefaultIntegerConfigOption =
947 ConfigOption::new_i64_with_default("integer-option", 12, "A flag option");
948
949 const _: StringConfigOption =
950 ConfigOption::new_str_no_default("integer-option", "A flag option");
951 const _: DefaultStringConfigOption =
952 ConfigOption::new_str_with_default("integer-option", "erik", "A flag option");
953 }
954
955 #[test]
956 fn test_type_serialize() {
957 assert_eq!(json!(ValueType::Integer), json!("int"));
958 assert_eq!(json!(ValueType::Flag), json!("flag"));
959 }
960}