1use std::path::{Component, Path, PathBuf};
2use std::sync::Arc;
3
4use anyhow::*;
5
6use crate::Map;
7
8#[derive(Clone)]
9pub(crate) struct TmxLoadContext<'a> {
10 relative: Arc<Path>,
11 lifetime: &'a (),
12}
13
14impl<'a> TmxLoadContext<'a> {
15 pub fn load_file<'p>(&'p self, path: impl AsRef<Path> + Send + 'p) -> Result<Vec<u8>> {
16 Ok(std::fs::read(self.file_path(path))?)
17 }
18
19 pub fn file_path(&self, path: impl AsRef<Path>) -> PathBuf {
20 let mut joined = PathBuf::new();
21 for c in self.relative.join(path.as_ref()).components() {
22 match c {
23 Component::Prefix(prefix) => joined.push(prefix.as_os_str()),
24 Component::RootDir => joined.push("/"),
25 Component::CurDir => (),
26 Component::ParentDir => {
27 joined.pop();
28 }
29 Component::Normal(c) => joined.push(c),
30 }
31 }
32 joined
33 }
34
35 pub fn file_directory(&self, path: impl AsRef<Path>) -> Self {
36 Self {
37 relative: if let Some(parent) = path.as_ref().parent() {
38 Arc::from(self.relative.join(parent))
39 } else {
40 self.relative.clone()
41 },
42 lifetime: self.lifetime,
43 }
44 }
45}
46
47pub fn load_from_file<P: AsRef<Path>>(path: P) -> Result<Map> {
49 let path = path.as_ref();
50 let context = ();
51 let context = if let Some(parent) = path.parent() {
52 TmxLoadContext {
53 relative: Arc::from(parent.to_path_buf()),
54 lifetime: &context,
55 }
56 } else {
57 TmxLoadContext {
58 relative: Path::new(".").to_path_buf().into(),
59 lifetime: &context,
60 }
61 };
62
63 let reader = xml::EventReader::new(std::fs::File::open(path)?);
64
65 Map::load_from_xml_reader(context, reader)
66}