1use serde::{Deserialize, Serialize};
17
18use crate::model::names::{
19 MacroName, ModuleName, ProjectName, RecordName, RelativePath, SeriesName, TagName,
20};
21use crate::model::snapshot::{FunArity, TypeArity};
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
27pub struct DiffPayload {
28 pub project: ProjectName,
29 pub from: TagName,
31 pub to: TagName,
33 pub modules_added: Vec<ModuleName>,
34 pub modules_removed: Vec<ModuleName>,
35 pub exports_added: Vec<QualifiedFunArity>,
36 pub exports_removed: Vec<QualifiedFunArity>,
37 pub types_added: Vec<QualifiedTypeArity>,
38 pub types_removed: Vec<QualifiedTypeArity>,
39 pub callbacks_added: Vec<QualifiedFunArity>,
40 pub callbacks_removed: Vec<QualifiedFunArity>,
41 pub headers_added: Vec<RelativePath>,
42 pub headers_removed: Vec<RelativePath>,
43 pub records_added: Vec<QualifiedRecord>,
44 pub records_removed: Vec<QualifiedRecord>,
45 #[serde(default, skip_serializing_if = "Vec::is_empty")]
46 pub versioned_machine_version_changes: Vec<VersionedMachineVersionChange>,
47 #[serde(default, skip_serializing_if = "Vec::is_empty")]
48 pub wire_constant_changes: Vec<WireConstantChange>,
49}
50
51impl DiffPayload {
52 #[must_use]
54 pub fn is_empty(&self) -> bool {
55 self.modules_added.is_empty()
56 && self.modules_removed.is_empty()
57 && self.exports_added.is_empty()
58 && self.exports_removed.is_empty()
59 && self.types_added.is_empty()
60 && self.types_removed.is_empty()
61 && self.callbacks_added.is_empty()
62 && self.callbacks_removed.is_empty()
63 && self.headers_added.is_empty()
64 && self.headers_removed.is_empty()
65 && self.records_added.is_empty()
66 && self.records_removed.is_empty()
67 && self.versioned_machine_version_changes.is_empty()
68 && self.wire_constant_changes.is_empty()
69 }
70
71 #[must_use]
73 pub fn breaking_removal_count(&self) -> usize {
74 self.modules_removed.len()
75 + self.exports_removed.len()
76 + self.callbacks_removed.len()
77 + self.types_removed.len()
78 + self.records_removed.len()
79 + self.headers_removed.len()
80 }
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
85#[serde(rename_all = "snake_case", tag = "kind")]
86pub enum VersionedMachineVersionChange {
87 Missing {
88 module: ModuleName,
89 side: String,
90 },
91 Drift {
92 module: ModuleName,
93 from: Option<u64>,
94 to: Option<u64>,
95 },
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
100#[serde(rename_all = "snake_case", tag = "kind")]
101pub enum WireConstantChange {
102 Missing {
103 module: ModuleName,
104 side: String,
105 macros: Vec<MacroName>,
106 },
107 Drift {
108 module: ModuleName,
109 macro_name: MacroName,
110 from: String,
111 to: String,
112 },
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
117pub struct QualifiedFunArity {
118 pub module: ModuleName,
119 #[serde(with = "crate::model::serde_util::display_from_str")]
120 pub fun_arity: FunArity,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
125pub struct QualifiedTypeArity {
126 pub module: ModuleName,
127 #[serde(with = "crate::model::serde_util::display_from_str")]
128 pub type_arity: TypeArity,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
133pub struct QualifiedRecord {
134 pub header: RelativePath,
135 pub record: RecordName,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
142pub struct CrossSeriesDiffPayload {
143 pub from_series: SeriesName,
145 pub to_series: SeriesName,
147 pub projects: Vec<DiffPayload>,
149}