1use std::marker::PhantomData;
16
17pub(crate) const MAX_TEXT_FIELD_BYTES: usize = 256;
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub enum ContextVisibility {
23 Public,
25 Diagnostic,
27 SecretPresenceOnly,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub enum FieldValueKind {
34 Text,
36 I64,
38 U64,
40 Bool,
42 Presence,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
74pub struct FieldSchema {
75 name: &'static str,
76 visibility: ContextVisibility,
77 value_kind: FieldValueKind,
78 text_byte_limit: Option<usize>,
79}
80
81impl FieldSchema {
82 pub(crate) const fn try_new(
83 name: &'static str,
84 visibility: ContextVisibility,
85 value_kind: FieldValueKind,
86 text_byte_limit: Option<usize>,
87 ) -> Option<Self> {
88 if !is_valid_field_name(name) || !is_valid_text_limit(value_kind, text_byte_limit) {
89 return None;
90 }
91 if matches!(visibility, ContextVisibility::SecretPresenceOnly)
92 && !matches!(value_kind, FieldValueKind::Presence)
93 {
94 return None;
95 }
96 Some(Self {
97 name,
98 visibility,
99 value_kind,
100 text_byte_limit,
101 })
102 }
103
104 #[inline]
106 pub const fn name(self) -> &'static str {
107 self.name
108 }
109
110 #[inline]
112 pub const fn visibility(self) -> ContextVisibility {
113 self.visibility
114 }
115
116 #[inline]
118 pub const fn value_kind(self) -> FieldValueKind {
119 self.value_kind
120 }
121
122 #[inline]
126 pub const fn text_byte_limit(self) -> Option<usize> {
127 self.text_byte_limit
128 }
129}
130
131#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
154pub struct FieldKey<T> {
155 schema: FieldSchema,
156 marker: PhantomData<fn() -> T>,
157}
158
159impl<T> Copy for FieldKey<T> {}
160
161impl<T> Clone for FieldKey<T> {
162 fn clone(&self) -> Self {
163 *self
164 }
165}
166
167impl<T> std::fmt::Debug for FieldKey<T> {
168 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 formatter.debug_tuple("FieldKey").field(&self.schema).finish()
170 }
171}
172
173impl<T> FieldKey<T> {
174 const fn new(schema: FieldSchema) -> Self {
175 Self {
176 schema,
177 marker: PhantomData,
178 }
179 }
180
181 #[inline]
183 pub const fn schema(self) -> FieldSchema {
184 self.schema
185 }
186}
187
188mod marker_seal {
189 pub trait Sealed {}
190}
191
192#[derive(Debug)]
194pub struct TextField {
195 _private: (),
196}
197
198#[derive(Debug)]
200pub struct I64Field {
201 _private: (),
202}
203
204#[derive(Debug)]
206pub struct U64Field {
207 _private: (),
208}
209
210#[derive(Debug)]
212pub struct BoolField {
213 _private: (),
214}
215
216#[derive(Debug)]
218pub struct SecretPresenceField {
219 _private: (),
220}
221
222impl marker_seal::Sealed for TextField {}
223impl marker_seal::Sealed for I64Field {}
224impl marker_seal::Sealed for U64Field {}
225impl marker_seal::Sealed for BoolField {}
226impl marker_seal::Sealed for SecretPresenceField {}
227
228trait FieldMarker: marker_seal::Sealed {
229 const KIND: FieldValueKind;
230}
231
232impl FieldMarker for TextField {
233 const KIND: FieldValueKind = FieldValueKind::Text;
234}
235
236impl FieldMarker for I64Field {
237 const KIND: FieldValueKind = FieldValueKind::I64;
238}
239
240impl FieldMarker for U64Field {
241 const KIND: FieldValueKind = FieldValueKind::U64;
242}
243
244impl FieldMarker for BoolField {
245 const KIND: FieldValueKind = FieldValueKind::Bool;
246}
247
248impl FieldMarker for SecretPresenceField {
249 const KIND: FieldValueKind = FieldValueKind::Presence;
250}
251
252const fn checked_key<T: FieldMarker>(schema: FieldSchema) -> FieldKey<T> {
253 if !same_value_kind(schema.value_kind(), T::KIND) {
254 panic!("field marker does not match schema value kind");
255 }
256 FieldKey::new(schema)
257}
258
259const fn same_value_kind(left: FieldValueKind, right: FieldValueKind) -> bool {
260 matches!(
261 (left, right),
262 (FieldValueKind::Text, FieldValueKind::Text)
263 | (FieldValueKind::I64, FieldValueKind::I64)
264 | (FieldValueKind::U64, FieldValueKind::U64)
265 | (FieldValueKind::Bool, FieldValueKind::Bool)
266 | (FieldValueKind::Presence, FieldValueKind::Presence)
267 )
268}
269
270const fn is_valid_text_limit(value_kind: FieldValueKind, limit: Option<usize>) -> bool {
271 match (value_kind, limit) {
272 (FieldValueKind::Text, Some(limit)) => limit > 0 && limit <= MAX_TEXT_FIELD_BYTES,
273 (FieldValueKind::Text, None) => false,
274 (_, None) => true,
275 (_, Some(_)) => false,
276 }
277}
278
279const fn is_valid_field_name(name: &str) -> bool {
280 let bytes = name.as_bytes();
281 if bytes.is_empty() {
282 return false;
283 }
284
285 let mut index = 0;
286 let mut starts_segment = true;
287 while index < bytes.len() {
288 let byte = bytes[index];
289 if starts_segment {
290 if !byte.is_ascii_lowercase() {
291 return false;
292 }
293 starts_segment = false;
294 } else if byte == b'_' {
295 starts_segment = true;
296 } else if !byte.is_ascii_lowercase() && !byte.is_ascii_digit() {
297 return false;
298 }
299 index += 1;
300 }
301 !starts_segment
302}
303
304macro_rules! define_field {
305 ($name:ident, $marker:ty, $external_name:literal, $visibility:path, $kind:path, $limit:expr, $docs:literal) => {
306 #[doc = $docs]
307 pub const $name: FieldKey<$marker> = {
308 const SCHEMA: FieldSchema = match FieldSchema::try_new($external_name, $visibility, $kind, $limit) {
309 Some(schema) => schema,
310 None => panic!("invalid context field schema"),
311 };
312 checked_key(SCHEMA)
313 };
314 };
315}
316
317pub mod fields {
323 use super::*;
324
325 define_field!(
326 ACTUAL_STATE,
327 TextField,
328 "actual",
329 ContextVisibility::Diagnostic,
330 FieldValueKind::Text,
331 Some(64),
332 "Actual client state."
333 );
334 define_field!(
335 ACTUAL_U64,
336 U64Field,
337 "actual",
338 ContextVisibility::Diagnostic,
339 FieldValueKind::U64,
340 None,
341 "Actual numeric version."
342 );
343 define_field!(
344 ACTUAL_BYTES,
345 U64Field,
346 "actual_bytes",
347 ContextVisibility::Public,
348 FieldValueKind::U64,
349 None,
350 "Actual message size in bytes."
351 );
352 define_field!(
353 ADDR,
354 TextField,
355 "addr",
356 ContextVisibility::Diagnostic,
357 FieldValueKind::Text,
358 Some(256),
359 "Network address used by a failed operation."
360 );
361 define_field!(
362 ALLOWED,
363 TextField,
364 "allowed",
365 ContextVisibility::Diagnostic,
366 FieldValueKind::Text,
367 Some(64),
368 "Allowed values for a validation failure."
369 );
370 define_field!(
371 ATTEMPTED,
372 BoolField,
373 "attempted",
374 ContextVisibility::Diagnostic,
375 FieldValueKind::Bool,
376 None,
377 "Whether installation was attempted."
378 );
379 define_field!(
380 BROKER,
381 TextField,
382 "broker",
383 ContextVisibility::Diagnostic,
384 FieldValueKind::Text,
385 Some(127),
386 "Broker identity involved in an operation."
387 );
388 define_field!(
389 BROKER_ADDR,
390 TextField,
391 "broker_addr",
392 ContextVisibility::Diagnostic,
393 FieldValueKind::Text,
394 Some(256),
395 "Broker address involved in an operation."
396 );
397 define_field!(
398 BROKER_CODE,
399 I64Field,
400 "broker_code",
401 ContextVisibility::Diagnostic,
402 FieldValueKind::I64,
403 None,
404 "Broker response code."
405 );
406 define_field!(
407 CLUSTER,
408 TextField,
409 "cluster",
410 ContextVisibility::Public,
411 FieldValueKind::Text,
412 Some(127),
413 "Cluster identity."
414 );
415 define_field!(
416 CLIENT_ROLE,
417 TextField,
418 "client_role",
419 ContextVisibility::Public,
420 FieldValueKind::Text,
421 Some(32),
422 "Client component role."
423 );
424 define_field!(
425 COMPONENT_NAME,
426 TextField,
427 "component",
428 ContextVisibility::Diagnostic,
429 FieldValueKind::Text,
430 Some(64),
431 "Component involved in a lifecycle failure."
432 );
433 define_field!(
434 CONSUMER,
435 TextField,
436 "consumer",
437 ContextVisibility::Diagnostic,
438 FieldValueKind::Text,
439 Some(127),
440 "Consumer identity."
441 );
442 define_field!(
443 CURRENT,
444 I64Field,
445 "current",
446 ContextVisibility::Public,
447 FieldValueKind::I64,
448 None,
449 "Current numeric value."
450 );
451 define_field!(
452 DURATION_MS,
453 U64Field,
454 "duration_ms",
455 ContextVisibility::Public,
456 FieldValueKind::U64,
457 None,
458 "Operation duration in milliseconds."
459 );
460 define_field!(
461 EXPECTED_STATE,
462 TextField,
463 "expected",
464 ContextVisibility::Diagnostic,
465 FieldValueKind::Text,
466 Some(64),
467 "Expected client state."
468 );
469 define_field!(
470 EXPECTED_U64,
471 U64Field,
472 "expected",
473 ContextVisibility::Diagnostic,
474 FieldValueKind::U64,
475 None,
476 "Expected numeric version."
477 );
478 define_field!(
479 FEATURE,
480 TextField,
481 "feature",
482 ContextVisibility::Public,
483 FieldValueKind::Text,
484 Some(64),
485 "Disabled feature name."
486 );
487 define_field!(
488 FILTER_KIND,
489 TextField,
490 "filter_kind",
491 ContextVisibility::Diagnostic,
492 FieldValueKind::Text,
493 Some(64),
494 "Filter failure classification."
495 );
496 define_field!(
497 FORMAT,
498 TextField,
499 "format",
500 ContextVisibility::Diagnostic,
501 FieldValueKind::Text,
502 Some(64),
503 "Serialization format classification."
504 );
505 define_field!(
506 FIELD,
507 TextField,
508 "field",
509 ContextVisibility::Public,
510 FieldValueKind::Text,
511 Some(64),
512 "Input field name."
513 );
514 define_field!(
515 FILTER_COMPILE_KIND,
516 TextField,
517 "filter_compile_kind",
518 ContextVisibility::Diagnostic,
519 FieldValueKind::Text,
520 Some(64),
521 "Filter compilation failure kind."
522 );
523 define_field!(
524 FILTER_COMPILE_POSITION,
525 U64Field,
526 "filter_compile_position",
527 ContextVisibility::Diagnostic,
528 FieldValueKind::U64,
529 None,
530 "Filter compilation byte position."
531 );
532 define_field!(
533 FILTER_COMPILE_SOURCE,
534 TextField,
535 "filter_compile_source",
536 ContextVisibility::Diagnostic,
537 FieldValueKind::Text,
538 Some(64),
539 "Filter compiler source classification."
540 );
541 define_field!(
542 FILTER_COMPILE_STAGE,
543 TextField,
544 "filter_compile_stage",
545 ContextVisibility::Diagnostic,
546 FieldValueKind::Text,
547 Some(64),
548 "Filter compilation stage."
549 );
550 define_field!(
551 GROUP,
552 TextField,
553 "group",
554 ContextVisibility::Public,
555 FieldValueKind::Text,
556 Some(127),
557 "Consumer group identity."
558 );
559 define_field!(
560 INSTALLED,
561 BoolField,
562 "installed",
563 ContextVisibility::Diagnostic,
564 FieldValueKind::Bool,
565 None,
566 "Whether a subscriber was installed."
567 );
568 define_field!(
569 INVARIANT,
570 TextField,
571 "invariant",
572 ContextVisibility::Diagnostic,
573 FieldValueKind::Text,
574 Some(128),
575 "Violated invariant classification."
576 );
577 define_field!(
578 KEY,
579 TextField,
580 "key",
581 ContextVisibility::Diagnostic,
582 FieldValueKind::Text,
583 Some(64),
584 "Configuration key name."
585 );
586 define_field!(
587 LEADER_ID,
588 U64Field,
589 "leader_id",
590 ContextVisibility::Diagnostic,
591 FieldValueKind::U64,
592 None,
593 "Controller leader identifier."
594 );
595 define_field!(
596 LIMIT,
597 U64Field,
598 "limit",
599 ContextVisibility::Diagnostic,
600 FieldValueKind::U64,
601 None,
602 "Capacity limit associated with a failure."
603 );
604 define_field!(
605 LIMIT_BYTES,
606 U64Field,
607 "limit_bytes",
608 ContextVisibility::Public,
609 FieldValueKind::U64,
610 None,
611 "Configured byte limit."
612 );
613 define_field!(
614 MASTER_ADDRESS,
615 TextField,
616 "master_address",
617 ContextVisibility::Diagnostic,
618 FieldValueKind::Text,
619 Some(256),
620 "Current master broker address."
621 );
622 define_field!(
623 MAX,
624 I64Field,
625 "max",
626 ContextVisibility::Public,
627 FieldValueKind::I64,
628 None,
629 "Maximum numeric value."
630 );
631 define_field!(
632 MAX_QUEUE_ID,
633 I64Field,
634 "max_queue_id",
635 ContextVisibility::Public,
636 FieldValueKind::I64,
637 None,
638 "Maximum queue identifier."
639 );
640 define_field!(
641 OFFSET,
642 I64Field,
643 "offset",
644 ContextVisibility::Diagnostic,
645 FieldValueKind::I64,
646 None,
647 "Storage or message offset."
648 );
649 define_field!(
650 OPERATION,
651 TextField,
652 "operation",
653 ContextVisibility::Public,
654 FieldValueKind::Text,
655 Some(64),
656 "Public operation classification."
657 );
658 define_field!(
659 OPERATION_DIAGNOSTIC,
660 TextField,
661 "operation",
662 ContextVisibility::Diagnostic,
663 FieldValueKind::Text,
664 Some(64),
665 "Diagnostic operation classification."
666 );
667 define_field!(
668 OBSERVABILITY_SIGNAL,
669 TextField,
670 "observability_signal",
671 ContextVisibility::Diagnostic,
672 FieldValueKind::Text,
673 Some(32),
674 "Observability signal classification."
675 );
676 define_field!(
677 ORDINAL,
678 U64Field,
679 "ordinal",
680 ContextVisibility::Public,
681 FieldValueKind::U64,
682 None,
683 "Protocol version ordinal."
684 );
685 define_field!(
686 PERMISSION_VALUE,
687 I64Field,
688 "value",
689 ContextVisibility::Public,
690 FieldValueKind::I64,
691 None,
692 "Invalid permission value."
693 );
694 define_field!(
695 PROPERTY,
696 TextField,
697 "property",
698 ContextVisibility::Public,
699 FieldValueKind::Text,
700 Some(127),
701 "Message property name."
702 );
703 define_field!(
704 PHASE,
705 TextField,
706 "phase",
707 ContextVisibility::Diagnostic,
708 FieldValueKind::Text,
709 Some(32),
710 "Operation phase at which the failure occurred."
711 );
712 define_field!(
713 POSITION,
714 U64Field,
715 "position",
716 ContextVisibility::Diagnostic,
717 FieldValueKind::U64,
718 None,
719 "Input position associated with a failure."
720 );
721 define_field!(
722 QUEUE_ID,
723 I64Field,
724 "queue_id",
725 ContextVisibility::Public,
726 FieldValueKind::I64,
727 None,
728 "Message queue identifier."
729 );
730 define_field!(
731 REQUEST_CODE,
732 I64Field,
733 "request_code",
734 ContextVisibility::Public,
735 FieldValueKind::I64,
736 None,
737 "RocketMQ request code."
738 );
739 define_field!(
740 REMOTE_ADDR,
741 TextField,
742 "remote_addr",
743 ContextVisibility::Diagnostic,
744 FieldValueKind::Text,
745 Some(256),
746 "Remote transport address."
747 );
748 define_field!(
749 REMOTE_CODE,
750 I64Field,
751 "remote_code",
752 ContextVisibility::Diagnostic,
753 FieldValueKind::I64,
754 None,
755 "Remote response code."
756 );
757 define_field!(
758 RESOURCE,
759 TextField,
760 "resource",
761 ContextVisibility::Public,
762 FieldValueKind::Text,
763 Some(127),
764 "Resource identity."
765 );
766 define_field!(
767 STORE_COMPONENT,
768 TextField,
769 "store_component",
770 ContextVisibility::Diagnostic,
771 FieldValueKind::Text,
772 Some(64),
773 "Storage component classification."
774 );
775 define_field!(
776 STORE_OPERATION,
777 TextField,
778 "store_operation",
779 ContextVisibility::Diagnostic,
780 FieldValueKind::Text,
781 Some(64),
782 "Storage operation classification."
783 );
784 define_field!(
785 SERIALIZATION_TYPE,
786 U64Field,
787 "serialization_type",
788 ContextVisibility::Public,
789 FieldValueKind::U64,
790 None,
791 "Protocol serialization type identifier."
792 );
793 define_field!(
794 TASK,
795 TextField,
796 "task",
797 ContextVisibility::Diagnostic,
798 FieldValueKind::Text,
799 Some(64),
800 "Background task classification."
801 );
802 define_field!(
803 TIMEOUT_MS,
804 U64Field,
805 "timeout_ms",
806 ContextVisibility::Public,
807 FieldValueKind::U64,
808 None,
809 "Timeout duration in milliseconds."
810 );
811 define_field!(
812 TOPIC,
813 TextField,
814 "topic",
815 ContextVisibility::Public,
816 FieldValueKind::Text,
817 Some(127),
818 "Topic identity."
819 );
820 define_field!(
821 DECLARED_SIZE,
822 I64Field,
823 "declared_size",
824 ContextVisibility::Diagnostic,
825 FieldValueKind::I64,
826 None,
827 "Declared record size."
828 );
829
830 define_field!(
831 AUTH_ERROR_PRESENT,
832 SecretPresenceField,
833 "auth_error",
834 ContextVisibility::SecretPresenceOnly,
835 FieldValueKind::Presence,
836 None,
837 "Presence of rendered authentication error detail."
838 );
839 define_field!(
840 CONTEXT_PRESENT,
841 SecretPresenceField,
842 "context",
843 ContextVisibility::SecretPresenceOnly,
844 FieldValueKind::Presence,
845 None,
846 "Presence of task context."
847 );
848 define_field!(
849 DETAIL_PRESENT,
850 SecretPresenceField,
851 "detail",
852 ContextVisibility::SecretPresenceOnly,
853 FieldValueKind::Presence,
854 None,
855 "Presence of arbitrary diagnostic detail."
856 );
857 define_field!(
858 CONTROLLER_ERROR_PRESENT,
859 SecretPresenceField,
860 "controller_error",
861 ContextVisibility::SecretPresenceOnly,
862 FieldValueKind::Presence,
863 None,
864 "Presence of rendered controller error detail."
865 );
866 define_field!(
867 CREDENTIALS_PRESENT,
868 SecretPresenceField,
869 "credentials_present",
870 ContextVisibility::SecretPresenceOnly,
871 FieldValueKind::Presence,
872 None,
873 "Presence of authentication credentials."
874 );
875 define_field!(
876 DOMAIN_ERROR_PRESENT,
877 SecretPresenceField,
878 "domain_error",
879 ContextVisibility::SecretPresenceOnly,
880 FieldValueKind::Presence,
881 None,
882 "Presence of rendered domain error detail."
883 );
884 define_field!(
885 ERROR_PRESENT,
886 SecretPresenceField,
887 "error",
888 ContextVisibility::SecretPresenceOnly,
889 FieldValueKind::Presence,
890 None,
891 "Presence of rendered error detail."
892 );
893 define_field!(
894 FILTER_PRESENT,
895 SecretPresenceField,
896 "filter",
897 ContextVisibility::SecretPresenceOnly,
898 FieldValueKind::Presence,
899 None,
900 "Presence of filter text."
901 );
902 define_field!(
903 FILTER_ERROR_PRESENT,
904 SecretPresenceField,
905 "filter_error",
906 ContextVisibility::SecretPresenceOnly,
907 FieldValueKind::Presence,
908 None,
909 "Presence of rendered filter error detail."
910 );
911 define_field!(
912 INTERNAL_ERROR_PRESENT,
913 SecretPresenceField,
914 "internal_error",
915 ContextVisibility::SecretPresenceOnly,
916 FieldValueKind::Presence,
917 None,
918 "Presence of rendered internal error detail."
919 );
920 define_field!(
921 HOST_PRESENT,
922 SecretPresenceField,
923 "host",
924 ContextVisibility::SecretPresenceOnly,
925 FieldValueKind::Presence,
926 None,
927 "Presence of a network host value."
928 );
929 define_field!(
930 INVALID_VALUE_PRESENT,
931 SecretPresenceField,
932 "invalid_value_present",
933 ContextVisibility::SecretPresenceOnly,
934 FieldValueKind::Presence,
935 None,
936 "Presence of an invalid secret-bearing value."
937 );
938 define_field!(
939 IO_ERROR_PRESENT,
940 SecretPresenceField,
941 "io_error",
942 ContextVisibility::SecretPresenceOnly,
943 FieldValueKind::Presence,
944 None,
945 "Presence of rendered I/O error detail."
946 );
947 define_field!(
948 MESSAGE_PRESENT,
949 SecretPresenceField,
950 "message",
951 ContextVisibility::SecretPresenceOnly,
952 FieldValueKind::Presence,
953 None,
954 "Presence of arbitrary error message detail."
955 );
956 define_field!(
957 PATH_PRESENT,
958 SecretPresenceField,
959 "path",
960 ContextVisibility::SecretPresenceOnly,
961 FieldValueKind::Presence,
962 None,
963 "Presence of a storage or configuration path."
964 );
965 define_field!(
966 PROTOCOL_ERROR_PRESENT,
967 SecretPresenceField,
968 "protocol_error",
969 ContextVisibility::SecretPresenceOnly,
970 FieldValueKind::Presence,
971 None,
972 "Presence of rendered protocol error detail."
973 );
974 define_field!(
975 REMOTE_ADDR_PRESENT,
976 SecretPresenceField,
977 "remote_addr",
978 ContextVisibility::SecretPresenceOnly,
979 FieldValueKind::Presence,
980 None,
981 "Presence of a remote transport address."
982 );
983 define_field!(
984 REASON_PRESENT,
985 SecretPresenceField,
986 "reason",
987 ContextVisibility::SecretPresenceOnly,
988 FieldValueKind::Presence,
989 None,
990 "Presence of arbitrary failure detail."
991 );
992 define_field!(
993 RPC_ERROR_PRESENT,
994 SecretPresenceField,
995 "rpc_error",
996 ContextVisibility::SecretPresenceOnly,
997 FieldValueKind::Presence,
998 None,
999 "Presence of rendered RPC error detail."
1000 );
1001 define_field!(
1002 SERIALIZATION_ERROR_PRESENT,
1003 SecretPresenceField,
1004 "serialization_error",
1005 ContextVisibility::SecretPresenceOnly,
1006 FieldValueKind::Presence,
1007 None,
1008 "Presence of rendered serialization error detail."
1009 );
1010 define_field!(
1011 SERVICE_ERROR_PRESENT,
1012 SecretPresenceField,
1013 "service_error",
1014 ContextVisibility::SecretPresenceOnly,
1015 FieldValueKind::Presence,
1016 None,
1017 "Presence of rendered service error detail."
1018 );
1019 define_field!(
1020 SOURCE_PRESENT,
1021 SecretPresenceField,
1022 "source_present",
1023 ContextVisibility::SecretPresenceOnly,
1024 FieldValueKind::Presence,
1025 None,
1026 "Presence of a typed source error."
1027 );
1028 define_field!(
1029 SOURCE_DETAIL_PRESENT,
1030 SecretPresenceField,
1031 "source",
1032 ContextVisibility::SecretPresenceOnly,
1033 FieldValueKind::Presence,
1034 None,
1035 "Presence of rendered source error detail."
1036 );
1037 define_field!(
1038 STORE_DETAIL_PRESENT,
1039 SecretPresenceField,
1040 "store_detail",
1041 ContextVisibility::SecretPresenceOnly,
1042 FieldValueKind::Presence,
1043 None,
1044 "Presence of storage diagnostic detail."
1045 );
1046 define_field!(
1047 VALUE_PRESENT,
1048 SecretPresenceField,
1049 "value",
1050 ContextVisibility::SecretPresenceOnly,
1051 FieldValueKind::Presence,
1052 None,
1053 "Presence of a configuration value."
1054 );
1055}
1056
1057#[cfg(test)]
1058mod tests {
1059 use super::*;
1060
1061 #[test]
1062 fn invalid_schemas_are_rejected() {
1063 for name in ["", "Upper", "two__parts", "trailing_", "9leading"] {
1064 assert_eq!(
1065 FieldSchema::try_new(name, ContextVisibility::Public, FieldValueKind::Text, Some(64)),
1066 None
1067 );
1068 }
1069 assert_eq!(
1070 FieldSchema::try_new("text", ContextVisibility::Public, FieldValueKind::Text, None),
1071 None
1072 );
1073 assert_eq!(
1074 FieldSchema::try_new("text", ContextVisibility::Public, FieldValueKind::Text, Some(0)),
1075 None
1076 );
1077 assert_eq!(
1078 FieldSchema::try_new("text", ContextVisibility::Public, FieldValueKind::Text, Some(257)),
1079 None
1080 );
1081 assert_eq!(
1082 FieldSchema::try_new("number", ContextVisibility::Public, FieldValueKind::U64, Some(8)),
1083 None
1084 );
1085 assert_eq!(
1086 FieldSchema::try_new(
1087 "secret",
1088 ContextVisibility::SecretPresenceOnly,
1089 FieldValueKind::Text,
1090 Some(64)
1091 ),
1092 None
1093 );
1094 }
1095
1096 #[test]
1097 fn same_external_name_can_have_distinct_immutable_schemas() {
1098 assert_eq!(
1099 fields::OPERATION.schema().name(),
1100 fields::OPERATION_DIAGNOSTIC.schema().name()
1101 );
1102 assert_ne!(fields::OPERATION.schema(), fields::OPERATION_DIAGNOSTIC.schema());
1103 }
1104}