1use std::{fs, path::Path};
5
6use serde::Deserialize;
7
8use crate::{
9 absent_nullable::AbsentNullable, assert_entry::AssertEntrySerial,
10 required_symbol::RequiredSymbolSerial, segment::SegmentSerial, settings::SettingsSerial,
11 symbol_assignment::SymbolAssignmentSerial, traits::Serial, vram_class::VramClassSerial,
12 AssertEntry, KeepSections, RequiredSymbol, Segment, Settings, SlinkyError, SymbolAssignment,
13 VramClass,
14};
15
16#[derive(PartialEq, Debug)]
17pub struct Document {
18 pub settings: Settings,
19
20 pub vram_classes: Vec<VramClass>,
21
22 pub segments: Vec<Segment>,
23
24 pub entry: Option<String>,
25 pub symbol_assignments: Vec<SymbolAssignment>,
26 pub required_symbols: Vec<RequiredSymbol>,
27 pub asserts: Vec<AssertEntry>,
28}
29
30impl Document {
31 pub fn read_file(path: &Path) -> Result<Self, SlinkyError> {
32 let f = match fs::File::open(path) {
33 Ok(f) => f,
34 Err(e) => {
35 return Err(SlinkyError::FailedFileOpen {
36 path: path.to_path_buf(),
37 description: e.to_string(),
38 })
39 }
40 };
41 let document_serial: DocumentSerial = match serde_yaml::from_reader(f) {
42 Ok(d) => d,
43 Err(e) => {
44 return Err(SlinkyError::FailedYamlParsing {
45 description: e.to_string(),
46 })
47 }
48 };
49
50 document_serial.unserialize()
51 }
52}
53
54#[derive(Deserialize, PartialEq, Debug)]
55#[serde(deny_unknown_fields)]
56pub(crate) struct DocumentSerial {
57 #[serde(default)]
58 pub settings: AbsentNullable<SettingsSerial>,
59
60 #[serde(default)]
61 pub vram_classes: AbsentNullable<Vec<VramClassSerial>>,
62
63 pub segments: Vec<SegmentSerial>,
64
65 #[serde(default)]
66 pub entry: AbsentNullable<String>,
67 #[serde(default)]
68 pub symbol_assignments: AbsentNullable<Vec<SymbolAssignmentSerial>>,
69 #[serde(default)]
70 pub required_symbols: AbsentNullable<Vec<RequiredSymbolSerial>>,
71 #[serde(default)]
72 pub asserts: AbsentNullable<Vec<AssertEntrySerial>>,
73}
74
75impl DocumentSerial {
76 pub fn unserialize(self) -> Result<Document, SlinkyError> {
77 let settings = match self.settings.get_non_null_no_default("settings")? {
78 None => Settings::default(),
79 Some(v) => v.unserialize()?,
80 };
81
82 if self.segments.is_empty() {
83 return Err(SlinkyError::EmptyValue {
84 name: "segments".to_string(),
85 });
86 }
87
88 let vram_classes = self
89 .vram_classes
90 .get_non_null("vram_classes", Vec::new)?
91 .unserialize(&settings)?;
92
93 let mut segments = self.segments.unserialize(&settings)?;
94
95 let entry = self.entry.get_non_null_no_default("entry")?;
96
97 let symbol_assignments = self
98 .symbol_assignments
99 .get_non_null("symbol_assignments", Vec::new)?
100 .unserialize(&settings)?;
101
102 let required_symbols = self
103 .required_symbols
104 .get_non_null("required_symbols", Vec::new)?
105 .unserialize(&settings)?;
106
107 let asserts = self
108 .asserts
109 .get_non_null("asserts", Vec::new)?
110 .unserialize(&settings)?;
111
112 for segment in segments.iter_mut() {
113 if let Some(vram_class_name) = &segment.vram_class {
114 if let Some(vram_class) = vram_classes.iter().find(|x| x.name == *vram_class_name) {
115 if vram_class.keep_sections != KeepSections::Absent {
116 segment.pass_down_keep_sections(&vram_class.keep_sections);
117 }
118 }
119 }
120 }
121
122 Ok(Document {
123 settings,
124 vram_classes,
125 segments,
126 entry,
127 symbol_assignments,
128 required_symbols,
129 asserts,
130 })
131 }
132}