1use std::borrow::Cow;
2use std::ffi::OsStr;
3use std::ffi::OsString;
4use std::fmt::Debug;
5use std::fmt::Display;
6use std::fmt::Write;
7use std::ops::Deref;
8use std::path::Path;
9use std::path::PathBuf;
10
11use crate::compile::PDX_BIN_NAME_ELF;
12use crate::compile::PDX_BIN_NAME_STEM;
13use crate::compile::PDX_PKG_EXT;
14use crate::compile::PDX_PKG_MANIFEST_FILENAME;
15use crate::compile::dylib_suffix_for_host;
16use crate::config::Env;
17
18
19pub trait Layout {
20 fn name(&self) -> &Name;
21
22
23 fn root(&self) -> &Path;
27
28 fn dest(&self) -> Cow<Path> { self.root().join(self.name().as_ref()).into() }
35
36 fn assets(&self) -> Cow<Path> { self.build().clone() }
38 fn assets_hash(&self) -> Cow<Path> { self.dest().join(".assets.hash").into() }
40 fn assets_plan(&self) -> Cow<Path> { self.dest().join("plan.json").into() }
41
42 fn build(&self) -> Cow<Path> { self.dest().join("build").into() }
52
53 fn manifest(&self) -> Cow<Path> { self.build().join(PDX_PKG_MANIFEST_FILENAME).into() }
55
56 fn binary(&self) -> Cow<Path> { self.build().join(PDX_BIN_NAME_ELF).into() }
58
59 fn library(&self) -> Cow<Path> {
63 self.build()
64 .join(PDX_BIN_NAME_STEM)
65 .with_extension(dylib_suffix_for_host())
66 .into()
67 }
68
69
70 fn artifact(&self) -> Cow<Path> {
72 self.root()
73 .join(self.name().as_ref())
74 .with_extension(PDX_PKG_EXT)
75 .into()
76 }
77
78
79 fn prepare(&mut self) -> std::io::Result<()> {
81 use std::fs::create_dir_all;
82 create_dir_all(self.root())?;
83 create_dir_all(self.dest())?;
84 create_dir_all(self.assets())?;
85 create_dir_all(self.build())?;
86 Ok(())
87 }
88}
89
90
91pub struct DefaultLayout {
93 name: Name,
94 root: PathBuf,
95 dest: PathBuf,
96 build: PathBuf,
97}
98
99
100impl DefaultLayout {
101 pub fn new(name: Name, root: PathBuf) -> Self {
102 let dest = root.join(name.as_path());
103 let build = dest.join("build");
104 Self { name,
105 root,
106 dest,
107 build }
108 }
109}
110
111
112impl Layout for DefaultLayout {
113 fn name(&self) -> &Name { &self.name }
114 fn root(&self) -> &Path { self.root.as_path() }
115 fn dest(&self) -> Cow<Path> { self.dest.as_path().into() }
116 fn build(&self) -> Cow<Path> { self.build.as_path().into() }
117}
118
119
120#[derive(Clone)]
121pub struct Name(OsString);
122
123
124impl Name {
125 pub fn with_names<S1, S2>(package_name: S1, crate_name: Option<S2>) -> Self
127 where S1: Into<OsString>,
128 S1: PartialEq<S2>,
129 S2: Into<OsString> {
130 let mut name: OsString = package_name.into();
131
132 if let Some(crate_name) = crate_name.map(Into::into) {
133 if name != crate_name {
134 name.write_fmt(format_args!("-{}", crate_name.to_string_lossy()))
135 .unwrap();
136 }
137 }
138
139 Name(name)
140 }
141
142 pub fn with_package<S>(package_name: S) -> Self
144 where S: Into<OsString> {
145 Name(package_name.into())
146 }
147
148
149 pub fn from_env(env: &Env) -> Self {
150 const UNKNOWN_CARGO_PKG_NAME: &str = "unknown";
151 let name = env.vars
152 .get("CARGO_BIN_NAME")
153 .or_else(|| env.vars.get("CARGO_CRATE_NAME"))
154 .or_else(|| env.vars.get("CARGO_PKG_NAME"))
155 .map(|s| s.as_str())
156 .unwrap_or(UNKNOWN_CARGO_PKG_NAME);
157 Self(name.into())
158 }
159}
160
161
162impl Display for Name {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 write!(f, "{}", self.0.to_string_lossy())
165 }
166}
167
168impl Debug for Name {
169 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.0) }
170}
171
172
173impl AsRef<OsStr> for Name {
174 fn as_ref(&self) -> &OsStr { self.0.as_ref() }
175}
176
177impl Name {
178 pub fn as_path(&self) -> &Path { Path::new(&self.0) }
179}
180
181impl Deref for Name {
182 type Target = Path;
183 fn deref(&self) -> &Self::Target { self.as_path() }
184}