pop_common/templates/
mod.rs

1// SPDX-License-Identifier: GPL-3.0
2
3use strum::{EnumMessage, EnumProperty, VariantArray};
4pub use thiserror::Error;
5
6/// Functions for extracting a template's files.
7pub mod extractor;
8/// Frontend template definitions.
9pub mod frontend;
10
11/// An error relating to templates or template variants.
12#[derive(Error, Debug)]
13pub enum Error {
14	/// The `Repository` property is missing from the template variant.
15	#[error("The `Repository` property is missing from the template variant")]
16	RepositoryMissing,
17	/// The `TypeMissing` property is missing from the template variant.
18	#[error("The `TypeMissing` property is missing from the template variant")]
19	TypeMissing,
20}
21
22/// A trait for templates. A template is a variant of a template type.
23pub trait Template:
24	Clone + Default + EnumMessage + EnumProperty + Eq + PartialEq + VariantArray
25{
26	/// The template's type property identifier.
27	const PROPERTY: &'static str = "Type";
28
29	/// Get the template's name.
30	fn name(&self) -> &str {
31		self.get_message().unwrap_or_default()
32	}
33
34	/// Get the description of the template.
35	fn description(&self) -> &str {
36		self.get_detailed_message().unwrap_or_default()
37	}
38
39	/// Get the template's repository url.
40	fn repository_url(&self) -> Result<&str, Error> {
41		self.get_str("Repository").ok_or(Error::RepositoryMissing)
42	}
43
44	/// Get the list of supported templates.
45	fn templates() -> &'static [Self] {
46		Self::VARIANTS
47	}
48
49	/// Get the type of the template.
50	fn template_type(&self) -> Result<&str, Error> {
51		self.get_str(Self::PROPERTY).ok_or(Error::TypeMissing)
52	}
53
54	/// Get whether the template is deprecated.
55	fn is_deprecated(&self) -> bool {
56		self.get_str("IsDeprecated") == Some("true")
57	}
58
59	/// Get the deprecation message for the template
60	fn deprecated_message(&self) -> &str {
61		self.get_str("DeprecatedMessage").unwrap_or_default()
62	}
63}
64
65/// A trait for defining overarching types of specific template variants.
66/// A Type has many Template variants.
67/// The method `default_template` should be implemented unless
68/// no default templates are desired.
69pub trait Type<T: Template>: Clone + Default + EnumMessage + Eq + PartialEq + VariantArray {
70	/// Get the list of types supported.
71	fn types() -> &'static [Self] {
72		Self::VARIANTS
73	}
74
75	/// Get types's name.
76	fn name(&self) -> &str {
77		self.get_message().unwrap_or_default()
78	}
79
80	/// Get the default template of the type.
81	fn default_template(&self) -> Option<T> {
82		None
83	}
84
85	/// Get the type's description.
86	fn description(&self) -> &str {
87		self.get_detailed_message().unwrap_or_default()
88	}
89
90	/// Get the list of templates of the type.
91	fn templates(&self) -> Vec<&T> {
92		T::VARIANTS
93			.iter()
94			.filter(|t| t.get_str(T::PROPERTY) == Some(self.name()) && !t.is_deprecated())
95			.collect()
96	}
97
98	/// Check the type provides the template.
99	fn provides(&self, template: &T) -> bool {
100		// Match explicitly on type name (message)
101		template.get_str(T::PROPERTY) == Some(self.name())
102	}
103}
104
105/// The possible values from the variants of an enum.
106#[macro_export]
107macro_rules! enum_variants {
108	($e: ty) => {{
109		PossibleValuesParser::new(
110			<$e>::VARIANTS
111				.iter()
112				.map(|p| PossibleValue::new(p.as_ref()))
113				.collect::<Vec<_>>(),
114		)
115		.try_map(|s| <$e>::from_str(&s).map_err(|e| format!("could not convert from {s} to type")))
116	}};
117}
118
119/// The possible values from the variants of an enum which are not deprecated.
120#[macro_export]
121macro_rules! enum_variants_without_deprecated {
122	($e:ty) => {{
123		<$e>::VARIANTS
124			.iter()
125			.filter(|variant| !variant.is_deprecated()) // Exclude deprecated variants for --help
126			.map(|v| v.as_ref())
127			.collect::<Vec<_>>()
128			.join(", ")
129	}};
130}