1use std::fmt;
2
3use semver::Version;
4
5use crate::{ident::Ident, Interface, Render, RenderOpts, World};
6
7#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
15pub struct Package {
16 name: PackageName,
18
19 items: Vec<PackageItem>,
21}
22
23impl Package {
24 pub fn new(name: PackageName) -> Self {
26 Self {
27 name,
28 items: vec![],
29 }
30 }
31
32 pub fn name(&self) -> &PackageName {
33 &self.name
34 }
35
36 pub fn set_name(&mut self, name: impl Into<PackageName>) {
37 self.name = name.into();
38 }
39
40 pub fn interface(&mut self, interface: Interface) {
42 self.items.push(PackageItem::Interface(interface))
43 }
44
45 pub fn world(&mut self, world: World) {
47 self.items.push(PackageItem::World(world))
48 }
49
50 pub fn item(&mut self, item: impl Into<PackageItem>) {
51 self.items.push(item.into());
52 }
53
54 pub fn items(&self) -> &[PackageItem] {
55 &self.items
56 }
57
58 pub fn items_mut(&mut self) -> &mut Vec<PackageItem> {
59 &mut self.items
60 }
61}
62
63impl Render for Package {
64 fn render(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
65 write!(f, "{}package {};\n", opts.spaces(), self.name)?;
66 for item in &self.items {
67 write!(f, "\n")?;
68 match item {
69 PackageItem::Interface(interface) => {
70 if let Some(docs) = &interface.docs {
71 docs.render(f, opts)?;
72 }
73 write!(f, "{}interface {} {{", opts.spaces(), interface.name)?;
74 if !interface.uses.is_empty() || !interface.items.is_empty() {
75 write!(f, "\n")?;
76 interface.uses.render(f, &opts.indent())?;
77 interface.items.render(f, &opts.indent())?;
78 write!(f, "{}}}\n", opts.spaces())?;
79 } else {
80 write!(f, "}}\n")?;
81 }
82 }
83 PackageItem::World(world) => {
84 world.render(f, opts)?;
85 }
86 }
87 }
88 Ok(())
89 }
90}
91
92impl fmt::Display for Package {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 self.render(f, &RenderOpts::default())
95 }
96}
97
98#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
99#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
100#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
101pub enum PackageItem {
102 Interface(Interface),
103 World(World),
104}
105
106#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
112#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
113#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
114pub struct PackageName {
115 namespace: String,
117 name: Ident,
119 version: Option<Version>,
121}
122
123impl PackageName {
124 pub fn new(
126 namespace: impl Into<String>,
127 name: impl Into<Ident>,
128 version: Option<Version>,
129 ) -> Self {
130 Self {
131 namespace: namespace.into(),
132 name: name.into(),
133 version,
134 }
135 }
136
137 pub fn namespace(&self) -> &str {
138 &self.namespace
139 }
140
141 pub fn set_namespace(&mut self, namespace: impl Into<String>) {
142 self.namespace = namespace.into();
143 }
144
145 pub fn name(&self) -> &Ident {
146 &self.name
147 }
148
149 pub fn set_name(&mut self, name: impl Into<Ident>) {
150 self.name = name.into()
151 }
152
153 pub fn version(&self) -> Option<&Version> {
154 self.version.as_ref()
155 }
156
157 pub fn set_version(&mut self, version: Option<impl Into<Version>>) {
158 self.version = version.map(|v| v.into())
159 }
160}
161
162impl From<PackageName> for String {
163 fn from(name: PackageName) -> String {
164 name.to_string()
165 }
166}
167
168impl fmt::Display for PackageName {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 write!(f, "{}:{}", self.namespace, self.name)?;
171 if let Some(version) = &self.version {
172 write!(f, "@{version}")?;
173 }
174 Ok(())
175 }
176}