1use std::fmt;
2use std::ops::{Deref, DerefMut};
3
4use semver::Version;
5
6use crate::{Interface, Render, RenderOpts, World, ident::Ident};
7
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
16pub struct Package {
17 name: PackageName,
19
20 items: Vec<PackageItem>,
22}
23
24impl Package {
25 pub fn new(name: PackageName) -> Self {
27 Self {
28 name,
29 items: vec![],
30 }
31 }
32
33 pub fn name(&self) -> &PackageName {
34 &self.name
35 }
36
37 pub fn set_name(&mut self, name: impl Into<PackageName>) {
38 self.name = name.into();
39 }
40
41 pub fn interface(&mut self, interface: Interface) {
43 self.items.push(PackageItem::Interface(interface))
44 }
45
46 pub fn world(&mut self, world: World) {
48 self.items.push(PackageItem::World(world))
49 }
50
51 pub fn item(&mut self, item: impl Into<PackageItem>) {
52 self.items.push(item.into());
53 }
54
55 pub fn items(&self) -> &[PackageItem] {
56 &self.items
57 }
58
59 pub fn items_mut(&mut self) -> &mut Vec<PackageItem> {
60 &mut self.items
61 }
62
63 fn render_items(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
65 for item in &self.items {
66 write!(f, "\n")?;
67 match item {
68 PackageItem::Interface(interface) => {
69 if let Some(docs) = &interface.docs {
70 docs.render(f, opts)?;
71 }
72 write!(f, "{}interface {} {{", opts.spaces(), interface.name)?;
73 if !interface.uses.is_empty() || !interface.items.is_empty() {
74 write!(f, "\n")?;
75 interface.uses.render(f, &opts.indent())?;
76 interface.items.render(f, &opts.indent())?;
77 write!(f, "{}}}\n", opts.spaces())?;
78 } else {
79 write!(f, "}}\n")?;
80 }
81 }
82 PackageItem::World(world) => {
83 world.render(f, opts)?;
84 }
85 }
86 }
87 Ok(())
88 }
89}
90
91impl Render for Package {
92 fn render(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
93 write!(f, "{}package {};\n", opts.spaces(), self.name)?;
94 self.render_items(f, opts)
95 }
96}
97
98impl fmt::Display for Package {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 self.render(f, &RenderOpts::default())
101 }
102}
103
104pub struct NestedPackage(Package);
106
107impl NestedPackage {
110 pub fn new(name: PackageName) -> Self {
112 Self(Package::new(name))
113 }
114}
115
116impl Deref for NestedPackage {
117 type Target = Package;
118
119 fn deref(&self) -> &Self::Target {
120 &self.0
121 }
122}
123
124impl DerefMut for NestedPackage {
125 fn deref_mut(&mut self) -> &mut Self::Target {
126 &mut self.0
127 }
128}
129
130impl Render for NestedPackage {
131 fn render(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
132 write!(f, "{}package {} {{\n", opts.spaces(), self.0.name)?;
133 self.0.render_items(f, &opts.indent())?;
134 write!(f, "{}}}\n", opts.spaces())
135 }
136}
137
138impl fmt::Display for NestedPackage {
139 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140 self.render(f, &RenderOpts::default())
141 }
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
145#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
146#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
147pub enum PackageItem {
148 Interface(Interface),
149 World(World),
150}
151
152#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
158#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
159#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
160pub struct PackageName {
161 namespace: String,
163 name: Ident,
165 version: Option<Version>,
167}
168
169impl PackageName {
170 pub fn new(
172 namespace: impl Into<String>,
173 name: impl Into<Ident>,
174 version: Option<Version>,
175 ) -> Self {
176 Self {
177 namespace: namespace.into(),
178 name: name.into(),
179 version,
180 }
181 }
182
183 pub fn namespace(&self) -> &str {
184 &self.namespace
185 }
186
187 pub fn set_namespace(&mut self, namespace: impl Into<String>) {
188 self.namespace = namespace.into();
189 }
190
191 pub fn name(&self) -> &Ident {
192 &self.name
193 }
194
195 pub fn set_name(&mut self, name: impl Into<Ident>) {
196 self.name = name.into()
197 }
198
199 pub fn version(&self) -> Option<&Version> {
200 self.version.as_ref()
201 }
202
203 pub fn set_version(&mut self, version: Option<impl Into<Version>>) {
204 self.version = version.map(|v| v.into())
205 }
206}
207
208impl From<PackageName> for String {
209 fn from(name: PackageName) -> String {
210 name.to_string()
211 }
212}
213
214impl fmt::Display for PackageName {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 write!(f, "{}:{}", self.namespace, self.name)?;
217 if let Some(version) = &self.version {
218 write!(f, "@{version}")?;
219 }
220 Ok(())
221 }
222}