1use std::hash::Hash;
2use std::borrow::Cow;
3use std::path::Path;
4
5use super::format::{AssetsOptions, AssetsRules, Ext, ExtraFields, ExtraValue, Manifest, Options, Support};
6use super::format::ws::OptionsDefault;
7
8
9pub trait PackageSource {
10 type Authors: ?Sized + std::slice::Join<&'static str, Output = String>;
11 type Metadata: MetadataSource;
12
13
14 fn name(&self) -> Cow<str>;
16 fn authors(&self) -> &Self::Authors;
18 fn version(&self) -> Cow<str>;
21 fn description(&self) -> Option<Cow<str>>;
23 fn metadata(&self) -> Option<&Self::Metadata>;
25
26 fn default_options(&self) -> Option<&OptionsDefault> { None }
33
34 fn assets_options(&self) -> AssetsOptions {
38 self.metadata()
39 .map(|m| m.options().with_workspace(self.default_options()))
40 .unwrap_or_default()
41 .assets
42 .to_owned()
43 }
44
45 fn bins(&self) -> &[&str];
47 fn examples(&self) -> &[&str];
49
50 fn manifest_path(&self) -> Cow<Path>;
52
53
54 fn manifest_for_crate(&self) -> impl ManifestSourceOptExt {
55 use super::format::Manifest;
56 use std::slice::Join;
57
58 let author = {
59 let author = Join::join(self.authors(), ", ");
60 if author.trim().is_empty() {
61 None
62 } else {
63 Some(author.into())
64 }
65 };
66 let version = Some(self.version());
67 let package = Manifest { name: Some(self.name()),
68 description: self.description(),
69 author,
70 version,
71 bundle_id: None,
72 image_path: None,
73 launch_sound_path: None,
74 content_warning: None,
75 content_warning2: None,
76 build_number: None };
77
78 if let Some(meta) = self.metadata() {
79 let manifest = meta.manifest();
80 let base = Ext { main: package,
81 extra: Default::default() };
82 let result = base.override_with_extra(manifest);
85 Ext { main: Manifest::from(&result),
86 extra: result.iter_extra()
87 .map(|m| {
88 m.into_iter()
89 .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().clone()))
90 .collect()
91 })
92 .unwrap_or_default() }
93 } else {
94 Ext { main: package.into_owned(),
95 extra: Default::default() }
96 }
97 }
98
99
100 fn manifest_override_for(&self, target: &str, dev: bool) -> Option<Ext<Manifest<String>>> {
102 let base = self.manifest_for_crate();
103
104 if let Some(root) = self.metadata() {
105 if dev {
106 if let Some(man) = root.example(target) {
107 Some(base.override_with_extra(man).into_owned())
108 } else {
109 log::debug!("dev-target override not found for {target:?}");
110 None
111 }
112 } else if let Some(man) = root.bin(target) {
113 Some(base.override_with_extra(man).into_owned())
114 } else {
115 log::debug!("target override not found for {target:?}");
116 None
117 }
118 } else {
119 Some(base.into_owned())
120 }
121 }
122
123 fn manifest_override_or_crate(&self, target: Option<&str>, dev: bool) -> Ext<Manifest<String>> {
125 target.and_then(|target| self.manifest_override_for(target, dev))
126 .unwrap_or_else(|| self.manifest_for_crate().into_owned())
127 }
128}
129
130
131pub trait MetadataSource {
132 type S: Eq + Hash;
133 type Manifest: ManifestSourceOptExt;
134 type TargetManifest: ManifestSourceOptExt + TargetId;
135
136 fn manifest(&self) -> &Self::Manifest;
138
139 fn bins(&self) -> &[Self::TargetManifest];
142 fn examples(&self) -> &[Self::TargetManifest];
145
146 fn bin<'t>(&'t self, target: &'_ str) -> Option<&'t Self::TargetManifest> {
149 self.bins().iter().find(|b| b.target() == target)
150 }
151 fn example<'t>(&'t self, target: &'_ str) -> Option<&'t Self::TargetManifest> {
154 self.examples().iter().find(|b| b.target() == target)
155 }
156
157 fn bin_targets(&self) -> impl IntoIterator<Item = &str>;
158 fn example_targets(&self) -> impl IntoIterator<Item = &str>;
159 fn all_targets(&self) -> impl IntoIterator<Item = &str> {
160 self.bin_targets().into_iter().chain(self.example_targets())
161 }
162
163 fn bins_iter(&self) -> Option<impl Iterator<Item = &Self::TargetManifest>> {
164 (!self.bins().is_empty()).then_some(self.bins().iter())
165 }
166 fn examples_iter(&self) -> Option<impl Iterator<Item = &Self::TargetManifest>> {
167 (!self.examples().is_empty()).then_some(self.examples().iter())
168 }
169
170 fn all_targets_iter(&self) -> impl Iterator<Item = &Self::TargetManifest> {
171 self.bins_iter()
172 .into_iter()
173 .flatten()
174 .chain(self.examples_iter().into_iter().flatten())
175 }
176
177 fn assets(&self) -> &AssetsRules<Self::S>;
178 fn dev_assets(&self) -> &AssetsRules<Self::S>;
179
180 fn options(&self) -> &Options;
181 fn assets_options(&self) -> Cow<'_, AssetsOptions>;
182
183 fn support(&self) -> &Support;
184
185 fn manifest_for_target(&self, target: &str, dev: bool) -> Option<impl ManifestSourceOptExt> {
188 let base = self.manifest();
191
192 if dev {
193 if let Some(target) = self.example(target) {
194 let trg = base.override_with_extra_ref(target);
195 Some(trg.into_owned())
196 } else {
197 None
198 }
199 } else if let Some(target) = self.bin(target) {
200 let trg = base.override_with_extra_ref(target);
201 Some(trg.into_owned())
202 } else {
203 None
204 }
205 }
206
207 fn manifest_for_target_any(&self, target: &str) -> Option<impl ManifestSourceOptExt> {
208 self.manifest_for_target(target, false)
209 .or_else(|| self.manifest_for_target(target, true))
210 .map(|m| m.into_manifest())
211 .or_else(|| Some(Ext::<Manifest<String>>::from(self.manifest())))
212 }
213}
214
215
216impl<T: MetadataSource> MetadataSource for &T {
217 type S = <T as MetadataSource>::S;
218 type Manifest = <T as MetadataSource>::Manifest;
219 type TargetManifest = <T as MetadataSource>::TargetManifest;
220
221
222 fn manifest(&self) -> &Self::Manifest { (*self).manifest() }
223
224 fn bins(&self) -> &[Self::TargetManifest] { <T as MetadataSource>::bins(*self) }
225 fn examples(&self) -> &[Self::TargetManifest] { <T as MetadataSource>::examples(*self) }
226
227 fn bin_targets(&self) -> impl IntoIterator<Item = &str> { (*self).bin_targets() }
228 fn example_targets(&self) -> impl IntoIterator<Item = &str> { (*self).example_targets() }
229
230 fn assets(&self) -> &AssetsRules<Self::S> { (*self).assets() }
231 fn dev_assets(&self) -> &AssetsRules<Self::S> { (*self).dev_assets() }
232 fn options(&self) -> &Options { (*self).options() }
233 fn assets_options(&self) -> Cow<'_, AssetsOptions> { (*self).assets_options() }
234 fn support(&self) -> &Support { (*self).support() }
235}
236
237
238pub trait ManifestSource {
239 fn name(&self) -> &str;
240 fn version(&self) -> &str;
241 fn author(&self) -> &str;
242 fn bundle_id(&self) -> &str;
243 fn description(&self) -> &str;
244 fn image_path(&self) -> &str;
245 fn launch_sound_path(&self) -> &str;
246 fn content_warning(&self) -> &str;
247 fn content_warning2(&self) -> &str;
248 fn build_number(&self) -> Option<usize>;
249}
250
251
252pub trait ManifestSourceOpt {
253 const MAY_BE_INCOMPLETE: bool;
255
256 fn name(&self) -> Option<&str>;
257 fn version(&self) -> Option<&str>;
258 fn author(&self) -> Option<&str>;
259 fn bundle_id(&self) -> Option<&str>;
260 fn description(&self) -> Option<&str>;
261 fn image_path(&self) -> Option<&str>;
262 fn launch_sound_path(&self) -> Option<&str>;
263 fn content_warning(&self) -> Option<&str>;
264 fn content_warning2(&self) -> Option<&str>;
265 fn build_number(&self) -> Option<usize>;
266
267 fn override_with<'a, Over>(&'a self, over: &'a Over) -> impl ManifestSourceOpt + 'a
268 where Over: ManifestSourceOpt {
269 use super::format::Manifest;
270
271 Manifest::<Cow<str>> { name: over.name().or(self.name()).map(Into::into),
272 version: over.version().or(self.version()).map(Into::into),
273 author: over.author().or(self.author()).map(Into::into),
274 bundle_id: over.bundle_id().or(self.bundle_id()).map(Into::into),
275 description: over.description().or(self.description()).map(Into::into),
276 image_path: over.image_path().or(self.image_path()).map(Into::into),
277 launch_sound_path: over.launch_sound_path()
278 .or(self.launch_sound_path())
279 .map(Into::into),
280 content_warning: over.content_warning().or(self.content_warning()).map(Into::into),
281 content_warning2: over.content_warning2()
282 .or(self.content_warning2())
283 .map(Into::into),
284 build_number: over.build_number().or(self.build_number()) }
285 }
286}
287
288
289pub trait ManifestSourceOptExt: ManifestSourceOpt {
290 const MAY_HAVE_EXTRA: bool;
291
292 fn has_extra(&self) -> bool { Self::MAY_HAVE_EXTRA && self.iter_extra().is_some() }
293 fn iter_extra(&self) -> Option<impl IntoIterator<Item = (impl AsRef<str>, impl AsRef<ExtraValue>)>>;
294
295 fn override_with_extra_ref<'t, Over>(&'t self, over: &'t Over) -> impl ManifestSourceOptExt + 't
296 where Over: ManifestSourceOptExt {
297 let manifest = self.override_with(over);
298 let extra = if over.has_extra() || self.has_extra() {
299 match (self.iter_extra(), over.iter_extra()) {
300 (None, None) => None,
301 (None, Some(extra)) => {
302 let result = extra.into_iter()
303 .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().clone()));
304 Some(result.collect())
305 },
306 (Some(extra), None) => {
307 let result = extra.into_iter()
308 .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().clone()));
309 Some(result.collect())
310 },
311 (Some(base), Some(extra)) => {
312 let mut result: ExtraFields<ExtraValue> = base.into_iter()
313 .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().clone()))
314 .collect();
315 result.extend(
316 extra.into_iter()
317 .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().clone())),
318 );
319 Some(result)
320 },
321 }.unwrap_or_else(|| ExtraFields::with_capacity(0))
322 } else {
323 ExtraFields::with_capacity(0)
324 };
325
326 Ext { main: manifest,
327 extra }
328 }
329
330
331 fn override_with_extra<Over: ManifestSourceOptExt>(&self,
332 overrider: &Over)
333 -> impl ManifestSourceOptExt + Cob<'static> {
334 self.override_with_extra_ref(overrider).into_manifest()
335 }
336}
337
338
339impl<T: ManifestSource> ManifestSourceOpt for T {
340 const MAY_BE_INCOMPLETE: bool = false;
341 fn name(&self) -> Option<&str> { Some(ManifestSource::name(self)) }
342 fn version(&self) -> Option<&str> { Some(ManifestSource::version(self)) }
343 fn author(&self) -> Option<&str> { Some(ManifestSource::author(self)) }
344 fn bundle_id(&self) -> Option<&str> { Some(ManifestSource::bundle_id(self)) }
345 fn description(&self) -> Option<&str> { Some(ManifestSource::description(self)) }
346 fn image_path(&self) -> Option<&str> { Some(ManifestSource::image_path(self)) }
347 fn launch_sound_path(&self) -> Option<&str> { Some(ManifestSource::launch_sound_path(self)) }
348 fn content_warning(&self) -> Option<&str> { Some(ManifestSource::content_warning(self)) }
349 fn content_warning2(&self) -> Option<&str> { Some(ManifestSource::content_warning2(self)) }
350 fn build_number(&self) -> Option<usize> { ManifestSource::build_number(self) }
351}
352
353impl<T: Clone + ManifestSourceOpt> ManifestSourceOpt for Cow<'_, T> {
354 const MAY_BE_INCOMPLETE: bool = T::MAY_BE_INCOMPLETE;
355
356 fn name(&self) -> Option<&str> { self.as_ref().name() }
357 fn version(&self) -> Option<&str> { self.as_ref().version() }
358 fn author(&self) -> Option<&str> { self.as_ref().author() }
359 fn bundle_id(&self) -> Option<&str> { self.as_ref().bundle_id() }
360 fn description(&self) -> Option<&str> { self.as_ref().description() }
361 fn image_path(&self) -> Option<&str> { self.as_ref().image_path() }
362 fn launch_sound_path(&self) -> Option<&str> { self.as_ref().launch_sound_path() }
363 fn content_warning(&self) -> Option<&str> { self.as_ref().content_warning() }
364 fn content_warning2(&self) -> Option<&str> { self.as_ref().content_warning2() }
365 fn build_number(&self) -> Option<usize> { self.as_ref().build_number() }
366}
367
368impl<'t, T: ManifestSourceOptExt> ManifestSourceOptExt for &'t T where &'t T: ManifestSourceOpt {
369 const MAY_HAVE_EXTRA: bool = true;
370
371 fn iter_extra(&self) -> Option<impl IntoIterator<Item = (impl AsRef<str>, impl AsRef<ExtraValue>)>> {
372 (*self).iter_extra()
373 }
374}
375
376
377pub trait TargetId {
378 fn target(&self) -> &str;
379}
380
381
382pub trait IntoManifest: Sized + ManifestSourceOptExt {
383 fn into_manifest(self) -> Ext<Manifest<String>> { self.into_owned() }
384}
385impl<T: ManifestSourceOptExt> IntoManifest for T {}
386
387
388pub(super) trait IntoOwned<T> {
389 fn into_owned(self) -> T;
390}
391
392
393pub trait Cob<'t>
396 where Self::Output: 't {
397 type Output;
398 fn as_borrow(&'t self) -> Self::Output;
399}
400
401impl<'t> Cob<'t> for str where Self: 't {
402 type Output = Cow<'t, str>;
403 fn as_borrow(&'t self) -> Self::Output { self.into() }
404}
405
406impl<'t, S: AsRef<str>> Cob<'t> for S {
407 type Output = Cow<'t, str>;
408 fn as_borrow(&'t self) -> Self::Output { self.as_ref().into() }
409}
410
411
412#[cfg(test)]
413mod tests {
414 use std::collections::HashMap;
415
416 use crate::metadata::format::Manifest;
417 use crate::metadata::format::Override;
418 use crate::metadata::format::Metadata;
419 use crate::metadata::format::MetadataInner;
420 use super::*;
421
422
423 impl<S: Default> Default for Manifest<S> {
425 fn default() -> Self {
426 Self { name: Default::default(),
427 version: Default::default(),
428 author: Default::default(),
429 bundle_id: Default::default(),
430 description: Default::default(),
431 image_path: Default::default(),
432 launch_sound_path: Default::default(),
433 content_warning: Default::default(),
434 content_warning2: Default::default(),
435 build_number: Default::default() }
436 }
437 }
438
439
440 #[test]
441 fn manifest_override() {
442 let base = Manifest { name: Some("Name"),
443 bundle_id: Some("dev.foo.bar"),
444 ..Default::default() };
445
446 let over = Manifest { name: Some("Over"),
447 bundle_id: None,
448 description: Some("description"),
449 ..Default::default() };
450
451
452 {
453 let res = base.override_with(&over);
454 assert_eq!(Some("Over"), res.name());
455 assert_eq!(Some("dev.foo.bar"), res.bundle_id());
456 assert_eq!(Some("description"), res.description());
457 }
458
459 {
460 let res = base.override_with(&over);
461 assert_eq!(Some("Over"), res.name());
462 assert_eq!(Some("dev.foo.bar"), res.bundle_id());
463 assert_eq!(Some("description"), res.description());
464 }
465
466 {
467 let res = base.override_with_extra(&over);
468 assert_eq!(Some("Over"), res.name());
469 assert_eq!(Some("dev.foo.bar"), res.bundle_id());
470 assert_eq!(Some("description"), res.description());
471 assert!(res.iter_extra().is_none());
472 }
473 }
474
475
476 #[test]
477 fn manifest_override_ext() {
478 let base = Manifest { name: Some("Name"),
479 bundle_id: Some("dev.foo.bar"),
480 ..Default::default() };
481
482 let mut extra = ExtraFields::with_capacity(1);
483 extra.insert("foo".into(), "bar".into());
484
485
486 let base = Ext { main: base, extra };
487
488 let over = Manifest { name: Some("Over"),
489 bundle_id: None,
490 description: Some("description"),
491 ..Default::default() };
492
493
494 {
495 let res = base.override_with(&over);
496 assert_eq!(Some("Over"), res.name());
497 assert_eq!(Some("dev.foo.bar"), res.bundle_id());
498 assert_eq!(Some("description"), res.description());
499 }
500
501 {
502 let res = base.override_with(&over);
503 assert_eq!(Some("Over"), res.name());
504 assert_eq!(Some("dev.foo.bar"), res.bundle_id());
505 assert_eq!(Some("description"), res.description());
506 }
507
508 {
509 let res = base.override_with_extra(&over);
510 assert_eq!(Some("Over"), res.name());
511 assert_eq!(Some("dev.foo.bar"), res.bundle_id());
512 assert_eq!(Some("description"), res.description());
513
514 assert!(res.iter_extra().is_some());
515 let (k, v) = res.iter_extra().unwrap().into_iter().next().unwrap();
516 assert_eq!("foo", k.as_ref());
517 assert_eq!(&ExtraValue::String("bar".into()), v.as_ref());
518 }
519 }
520
521
522 struct CrateInfoNoMeta;
523 impl PackageSource for CrateInfoNoMeta {
524 type Authors = [&'static str];
525 type Metadata = Metadata<String>;
526
527 fn name(&self) -> Cow<str> { "Name".into() }
528 fn authors(&self) -> &Self::Authors { &["John"] }
529 fn version(&self) -> Cow<str> { "0.0.0".into() }
530 fn description(&self) -> Option<Cow<str>> { None }
531 fn bins(&self) -> &[&str] { &[SOME_TARGET] }
532 fn examples(&self) -> &[&str] { &[] }
533 fn metadata(&self) -> Option<&Self::Metadata> { None }
534
535 fn manifest_path(&self) -> Cow<Path> { Cow::Borrowed(Path::new("Cargo.toml")) }
536 }
537
538 #[test]
539 fn manifest_for_base() {
540 let base = CrateInfoNoMeta.manifest_for_crate();
541 let spec = CrateInfoNoMeta.manifest_override_or_crate("target".into(), false);
542 let opt = CrateInfoNoMeta.manifest_override_for("target", false);
543 assert_eq!(opt, Some(spec.to_owned()));
544 assert_eq!(spec, base.into_owned());
545 }
546
547
548 struct CrateInfo(Metadata);
549 impl CrateInfo {
550 fn new() -> Self {
551 let base = Manifest { name: Some("Meta Name"),
552 bundle_id: Some("crate.id"),
553 ..Default::default() };
554
555 let mut extra = ExtraFields::with_capacity(1);
556 extra.insert("foo".into(), "bar".into());
557 assert!(!extra.is_empty());
558
559 let manifest = Ext { main: base, extra }.into_owned();
560 assert!(manifest.has_extra());
561
562 let bins = {
563 let base = Manifest { name: Some("Bin Name"),
564 author: Some("Alex"),
565 bundle_id: Some("bin.id"),
566 description: Some("description"),
567 ..Default::default() };
568
569 let mut extra = ExtraFields::with_capacity(1);
570 extra.insert("boo".into(), 42_usize.into());
571
572
573 let manifest = Ext { main: base, extra }.into_owned();
574 vec![Override { target: SOME_TARGET.to_owned(),
575 manifest }]
576 };
577
578 let meta = Metadata { inner: MetadataInner { manifest,
579 bins,
580 examples: vec![],
581 assets: Default::default(),
582 dev_assets: Default::default(),
583 options: Default::default(),
584 support: Default::default() } };
585
586 Self(meta)
587 }
588 }
589
590 impl PackageSource for CrateInfo {
591 type Authors = [&'static str];
592 type Metadata = Metadata<String>;
593
594 fn name(&self) -> Cow<str> { "Crate Name".into() }
595 fn authors(&self) -> &[&'static str] { &["John"] }
596 fn version(&self) -> Cow<str> { "0.0.0".into() }
597 fn description(&self) -> Option<Cow<str>> { None }
598
599 fn bins(&self) -> &[&str] { &[SOME_TARGET] }
600 fn examples(&self) -> &[&str] { &[] }
601
602 fn manifest_path(&self) -> Cow<Path> { Cow::Borrowed(Path::new("Cargo.toml")) }
603
604 fn metadata(&self) -> Option<&Self::Metadata> { Some(&self.0) }
605 }
606
607 const SOME_TARGET: &str = "some-target";
608
609 #[test]
610 fn manifest_for_crate() {
611 let base_src = CrateInfo::new();
612 let base = base_src.manifest_for_crate();
613 assert_eq!(Some("Meta Name"), base.name());
614 assert_eq!(Some("John"), base.author());
615 assert_eq!(Some("0.0.0"), base.version());
616 assert_eq!(Some("crate.id"), base.bundle_id());
617 assert!(base.description().is_none());
618 assert!(base.has_extra());
619 let extra = base.iter_extra()
620 .unwrap()
621 .into_iter()
622 .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().to_owned()))
623 .collect::<HashMap<_, _>>();
624 assert_eq!(1, extra.len());
625 assert_eq!(Some(&"bar".into()), extra.get("foo"));
626 }
627
628 #[test]
629 fn manifest_for_target_wrong_no_meta() {
630 let spec = CrateInfoNoMeta.manifest_override_or_crate(Some("WRONG"), false);
631
632 assert_eq!(Some("Name"), spec.name());
633 assert_eq!(Some("John"), spec.author());
634 assert_eq!(Some("0.0.0"), spec.version());
635 assert!(spec.bundle_id().is_none());
636 }
637
638 #[test]
639 fn manifest_for_target_wrong() {
640 let base_src = CrateInfo::new();
641 let base = base_src.manifest_for_crate();
642 let spec = base_src.manifest_override_or_crate(Some("WRONG"), false);
643 assert_eq!(Some("Meta Name"), spec.name());
644 assert_eq!(Some("John"), spec.author());
645 assert_eq!(Some("0.0.0"), spec.version());
646 assert_eq!(Some("crate.id"), spec.bundle_id());
647 assert_eq!(spec, base.into_owned());
648 }
649
650 #[test]
651 fn manifest_for_target_bin() {
652 let base_src = CrateInfo::new();
653 let spec = base_src.manifest_override_or_crate(SOME_TARGET.into(), false);
654 assert_eq!(Some("Bin Name"), spec.name());
655 assert_eq!(Some("Alex"), spec.author());
656 assert_eq!(Some("0.0.0"), spec.version());
657 assert_eq!(Some("bin.id"), spec.bundle_id());
658 assert_eq!(Some("description"), spec.description());
659 let extra = spec.iter_extra()
660 .unwrap()
661 .into_iter()
662 .map(|(k, v)| (k.as_ref().to_owned(), v.as_ref().to_owned()))
663 .collect::<HashMap<_, _>>();
664 assert_eq!(2, extra.len());
665 assert_eq!(Some(&"bar".into()), extra.get("foo"));
666 assert_eq!(Some(&42_usize.into()), extra.get("boo"));
667 }
668}