1use serde::de::{self, IgnoredAny, SeqAccess, Visitor};
6use serde::ser::{SerializeTuple, Serializer};
7use serde::{Deserialize, Deserializer, Serialize};
8use std::borrow::Cow;
9use std::fmt;
10
11use crate::format_version::{DeclaredRelease, ReleaseTriplet, deserialize_declared_release};
12
13use super::Attrs;
14use super::naming::Path;
15use super::package::{PackageDefinition, PackageSpecification, SpecsModuleEntry};
16use super::types::Type;
17
18#[derive(Debug, Clone, PartialEq)]
20pub struct Distribution {
21 pub format_version: u32,
22 pub distribution: DistributionBody,
23}
24
25impl Distribution {
26 pub fn emitted_format_version(&self) -> serde_json::Value {
30 match &self.distribution {
31 DistributionBody::Library(..) => serde_json::Value::from(3u32),
32 DistributionBody::Specs(..) => serde_json::Value::from("3.1.0"),
33 }
34 }
35}
36
37impl Serialize for Distribution {
38 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
39 where
40 S: Serializer,
41 {
42 use serde::ser::SerializeStruct;
43
44 let mut state = serializer.serialize_struct("Distribution", 2)?;
45 state.serialize_field("formatVersion", &self.emitted_format_version())?;
46 state.serialize_field("distribution", &self.distribution)?;
47 state.end()
48 }
49}
50
51pub const SPECS_FIRST_RELEASE: ReleaseTriplet = ReleaseTriplet::new(3, 1, 0);
53
54const SPECS_BEFORE_3_1: &str = "a v3 Specs distribution needs formatVersion 3.1.0 or later";
55
56pub fn check_specs_release(declared: &DeclaredRelease) -> Result<(), String> {
62 if declared.release < SPECS_FIRST_RELEASE {
63 return Err(format!("{SPECS_BEFORE_3_1}, found {}", declared.declared));
64 }
65 Ok(())
66}
67
68pub fn is_specs_before_3_1(message: &str) -> bool {
70 message.starts_with(SPECS_BEFORE_3_1)
71}
72
73impl<'de> Deserialize<'de> for Distribution {
74 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
75 where
76 D: Deserializer<'de>,
77 {
78 #[derive(Deserialize)]
79 #[serde(rename_all = "camelCase")]
80 struct DistributionFields {
81 #[serde(deserialize_with = "deserialize_declared_release")]
82 format_version: DeclaredRelease,
83 distribution: DistributionBody,
84 }
85 let fields = DistributionFields::deserialize(deserializer)?;
86 if let DistributionBody::Specs(..) = fields.distribution {
87 check_specs_release(&fields.format_version).map_err(de::Error::custom)?;
88 }
89 Ok(Self {
90 format_version: fields.format_version.release.major(),
91 distribution: fields.distribution,
92 })
93 }
94}
95
96#[derive(Debug, Clone, PartialEq)]
98pub enum DistributionBody {
99 Library(
100 Path,
101 Vec<(Path, PackageSpecification<Attrs>)>,
102 PackageDefinition<Attrs, Type<Attrs>>,
103 ),
104 Specs(
107 Path,
108 Vec<(Path, PackageSpecification<Attrs>)>,
109 PackageSpecification<Attrs>,
110 ),
111}
112
113impl Serialize for DistributionBody {
114 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
115 where
116 S: Serializer,
117 {
118 match self {
119 DistributionBody::Library(path, deps, package) => {
120 let mut tuple = serializer.serialize_tuple(4)?;
121 tuple.serialize_element("Library")?;
122 tuple.serialize_element(path)?;
123 tuple.serialize_element(deps)?;
124 tuple.serialize_element(package)?;
125 tuple.end()
126 }
127 DistributionBody::Specs(path, deps, spec) => {
128 let mut tuple = serializer.serialize_tuple(4)?;
129 tuple.serialize_element("Specs")?;
130 tuple.serialize_element(path)?;
131 tuple.serialize_element(deps)?;
132 tuple.serialize_element(spec)?;
133 tuple.end()
134 }
135 }
136 }
137}
138
139impl<'de> Deserialize<'de> for DistributionBody {
140 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
141 where
142 D: Deserializer<'de>,
143 {
144 struct DistributionBodyVisitor;
145
146 impl<'de> Visitor<'de> for DistributionBodyVisitor {
147 type Value = DistributionBody;
148
149 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
150 formatter.write_str(
151 r#"a DistributionBody array ["Library", path, deps, package] or ["Specs", path, deps, spec]"#,
152 )
153 }
154
155 fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
156 where
157 V: SeqAccess<'de>,
158 {
159 let tag: Cow<'de, str> = seq
160 .next_element()?
161 .ok_or_else(|| de::Error::invalid_length(0, &self))?;
162
163 match tag.as_ref() {
164 "Library" | "library" => {
165 let path = seq
166 .next_element::<Path>()?
167 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
168 let deps = seq
169 .next_element::<Vec<(Path, PackageSpecification<Attrs>)>>()?
170 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
171 let package = seq
172 .next_element::<PackageDefinition<Attrs, Type<Attrs>>>()?
173 .ok_or_else(|| de::Error::invalid_length(3, &self))?;
174
175 if let Some(IgnoredAny) = seq.next_element()? {
176 return Err(de::Error::custom(
177 "Expected end of DistributionBody array",
178 ));
179 }
180
181 Ok(DistributionBody::Library(path, deps, package))
182 }
183 "Specs" | "specs" => {
184 let path = seq
185 .next_element::<Path>()?
186 .ok_or_else(|| de::Error::invalid_length(1, &self))?;
187 let deps = seq
188 .next_element::<Vec<(Path, PackageSpecification<Attrs>)>>()?
189 .ok_or_else(|| de::Error::invalid_length(2, &self))?;
190 let SpecsPackage { modules } = seq
191 .next_element::<SpecsPackage>()?
192 .ok_or_else(|| de::Error::invalid_length(3, &self))?;
193 let spec = PackageSpecification {
194 modules: modules.into_iter().map(Into::into).collect(),
195 };
196
197 if let Some(IgnoredAny) = seq.next_element()? {
198 return Err(de::Error::custom(
199 "Expected end of DistributionBody array",
200 ));
201 }
202
203 Ok(DistributionBody::Specs(path, deps, spec))
204 }
205 _ => Err(de::Error::unknown_variant(
206 tag.as_ref(),
207 &["Library", "Specs"],
208 )),
209 }
210 }
211 }
212
213 deserializer.deserialize_seq(DistributionBodyVisitor)
214 }
215}
216
217#[derive(Deserialize)]
220struct SpecsPackage {
221 modules: Vec<SpecsModuleEntry<Attrs>>,
222}
223
224#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
226pub enum LibraryTag {
227 #[serde(alias = "library")]
228 Library,
229}