1use serde::{Deserialize, Serialize};
10
11pub use vyre_foundation::soundness::{
12 validate_dynamic_pipeline, validate_dynamic_primitive, validate_pipeline, validate_primitive,
13 DynamicPrimitiveSoundness, DynamicSoundnessViolation, PrecisionContract, PrimitiveSoundness,
14 Soundness, SoundnessTagged, SoundnessViolation,
15};
16
17pub const SHARED_FACT_SCHEMA_VERSION: u16 = 1;
19
20#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
22pub enum SharedFactKind {
23 Source,
25 Sink,
27 Taint,
29 Sanitizer,
31 GraphEdge,
33 BorrowLoan,
35 BorrowOrigin,
37 BorrowSubset,
39 Dominance,
41 Range,
43 Witness,
45}
46
47impl SharedFactKind {
48 #[must_use]
50 pub const fn wire_tag(self) -> &'static str {
51 match self {
52 Self::Source => "source",
53 Self::Sink => "sink",
54 Self::Taint => "taint",
55 Self::Sanitizer => "sanitizer",
56 Self::GraphEdge => "graph_edge",
57 Self::BorrowLoan => "borrow_loan",
58 Self::BorrowOrigin => "borrow_origin",
59 Self::BorrowSubset => "borrow_subset",
60 Self::Dominance => "dominance",
61 Self::Range => "range",
62 Self::Witness => "witness",
63 }
64 }
65}
66
67#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
69pub struct SharedFactHeader {
70 pub schema_version: u16,
72 pub producer: String,
74 pub kind: SharedFactKind,
76 pub fact_id: u64,
78 pub subject: u64,
80 pub object: Option<u64>,
82 pub aux: Option<u64>,
84 pub file_id: u32,
86 pub start_byte: u32,
88 pub end_byte: u32,
90 pub soundness: Soundness,
92}
93
94impl SharedFactHeader {
95 #[must_use]
97 pub fn new(
98 producer: impl Into<String>,
99 kind: SharedFactKind,
100 fact_id: u64,
101 subject: u64,
102 soundness: Soundness,
103 ) -> Self {
104 Self {
105 schema_version: SHARED_FACT_SCHEMA_VERSION,
106 producer: producer.into(),
107 kind,
108 fact_id,
109 subject,
110 object: None,
111 aux: None,
112 file_id: 0,
113 start_byte: 0,
114 end_byte: 0,
115 soundness,
116 }
117 }
118
119 #[must_use]
121 pub const fn with_object(mut self, object: u64) -> Self {
122 self.object = Some(object);
123 self
124 }
125
126 #[must_use]
128 pub const fn with_aux(mut self, aux: u64) -> Self {
129 self.aux = Some(aux);
130 self
131 }
132
133 #[must_use]
135 pub const fn with_span(mut self, file_id: u32, start_byte: u32, end_byte: u32) -> Self {
136 self.file_id = file_id;
137 self.start_byte = start_byte;
138 self.end_byte = end_byte;
139 self
140 }
141
142 #[must_use]
144 pub fn wire_header(&self) -> String {
145 format!(
146 "schema=v{};producer={};kind={};fact_id={};subject={};object={};aux={};file={};start={};end={};soundness={:?}",
147 self.schema_version,
148 self.producer,
149 self.kind.wire_tag(),
150 self.fact_id,
151 self.subject,
152 self.object.unwrap_or(0),
153 self.aux.unwrap_or(0),
154 self.file_id,
155 self.start_byte,
156 self.end_byte,
157 self.soundness
158 )
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn c_security_source_fact_header_is_exact() {
168 let header = SharedFactHeader::new("c-c11", SharedFactKind::Source, 1, 42, Soundness::Exact)
169 .with_span(7, 100, 120);
170
171 assert_eq!(
172 header.wire_header(),
173 "schema=v1;producer=c-c11;kind=source;fact_id=1;subject=42;object=0;aux=0;file=7;start=100;end=120;soundness=Exact"
174 );
175 }
176
177 #[test]
178 fn rust_borrow_subset_fact_header_is_exact() {
179 let header = SharedFactHeader::new(
180 "rustc-nll",
181 SharedFactKind::BorrowSubset,
182 9,
183 3,
184 Soundness::Exact,
185 )
186 .with_object(5)
187 .with_aux(11);
188
189 assert_eq!(
190 header.wire_header(),
191 "schema=v1;producer=rustc-nll;kind=borrow_subset;fact_id=9;subject=3;object=5;aux=11;file=0;start=0;end=0;soundness=Exact"
192 );
193 }
194
195 #[test]
196 fn weir_witness_fact_header_is_exact() {
197 let header = SharedFactHeader::new("weir", SharedFactKind::Witness, 13, 21, Soundness::Exact)
198 .with_object(34)
199 .with_aux(55);
200
201 assert_eq!(
202 header.wire_header(),
203 "schema=v1;producer=weir;kind=witness;fact_id=13;subject=21;object=34;aux=55;file=0;start=0;end=0;soundness=Exact"
204 );
205 }
206}