1use crate::{LayerTrait, PathDataTrait, PathTrait, Transforms};
2use std::collections::BTreeMap;
3
4#[allow(clippy::module_inception)]
5mod document;
6mod flattened_document;
7mod metadata;
8
9use crate::document_to_svg_doc;
10use crate::stats::LayerStats;
11pub use document::Document;
12pub use flattened_document::FlattenedDocument;
13pub use metadata::DocumentMetadata;
14
15pub type LayerID = usize;
16
17pub trait DocumentTrait<L: LayerTrait<P, D>, P: PathTrait<D>, D: PathDataTrait>:
18 Transforms
19{
20 fn layers(&self) -> &BTreeMap<LayerID, L>;
21
22 fn layers_mut(&mut self) -> &mut BTreeMap<LayerID, L>;
23
24 fn metadata(&self) -> &DocumentMetadata;
25
26 fn metadata_mut(&mut self) -> &mut DocumentMetadata;
27
28 fn push_path(&mut self, id: LayerID, path: impl Into<P>) {
29 self.get_mut(id).push_path(path.into());
30 }
31
32 fn try_get(&self, id: LayerID) -> Option<&L> {
33 self.layers().get(&id)
34 }
35
36 #[must_use]
37 fn get_mut(&mut self, id: LayerID) -> &mut L {
38 self.layers_mut().entry(id).or_insert_with(|| L::default())
39 }
40
41 fn ensure_exists(&mut self, id: LayerID) {
42 let _ = self.get_mut(id);
43 }
44
45 fn for_each<F>(&mut self, f: F)
46 where
47 F: Fn(&mut L),
48 {
49 self.layers_mut().values_mut().for_each(f);
50 }
51
52 fn merge_layers(&mut self) {
54 if let Some((_, mut layer)) = self.layers_mut().pop_first() {
55 while let Some((_, other)) = self.layers_mut().pop_first() {
56 layer.merge(&other);
57 }
58
59 self.layers_mut().insert(0, layer);
60 }
61 }
62
63 #[must_use]
64 fn bounds(&self) -> Option<kurbo::Rect> {
65 if self.layers().is_empty() {
66 return None;
67 }
68
69 let mut values = self.layers().values();
70 let first = values.next().expect("not empty").bounds();
71 values.fold(first, |acc, layer| match (acc, layer.bounds()) {
72 (Some(acc), Some(layer)) => Some(acc.union(layer)),
73 (Some(acc), None) => Some(acc),
74 (None, Some(path)) => Some(path),
75 (None, None) => None,
76 })
77 }
78
79 #[must_use]
80 fn stats(&self) -> BTreeMap<LayerID, LayerStats> {
81 self.layers()
82 .iter()
83 .map(|(id, layer)| (*id, layer.stats()))
84 .collect()
85 }
86
87 fn to_svg_string(&self) -> Result<String, std::fmt::Error> {
88 use std::fmt::Write;
89
90 let doc = document_to_svg_doc(self);
91 let mut svg = String::new();
92 write!(svg, "{doc}").map(|()| svg)
93 }
94 fn to_svg(&self, writer: impl std::io::Write) -> std::io::Result<()> {
95 let doc = document_to_svg_doc(self);
96 svg::write(writer, &doc)
97 }
98
99 fn to_svg_file(&self, file_path: impl AsRef<std::path::Path>) -> std::io::Result<()> {
100 let file = std::io::BufWriter::new(std::fs::File::create(file_path)?);
101 self.to_svg(file)
102 }
103}