altium_format/api/generic/
binary_record.rs1use indexmap::IndexMap;
4
5use super::Value;
6use crate::records::pcb::PcbObjectId;
7
8#[derive(Debug, Clone)]
13pub struct BinaryRecord {
14 object_id: PcbObjectId,
16 raw_data: Vec<u8>,
18 fields: Option<IndexMap<String, Value>>,
20 modified: bool,
22}
23
24impl BinaryRecord {
25 pub fn from_binary(object_id: PcbObjectId, data: Vec<u8>) -> Self {
27 BinaryRecord {
28 object_id,
29 raw_data: data,
30 fields: None,
31 modified: false,
32 }
33 }
34
35 pub fn from_binary_with_fields(
37 object_id: PcbObjectId,
38 data: Vec<u8>,
39 fields: IndexMap<String, Value>,
40 ) -> Self {
41 BinaryRecord {
42 object_id,
43 raw_data: data,
44 fields: Some(fields),
45 modified: false,
46 }
47 }
48
49 pub fn object_id(&self) -> PcbObjectId {
51 self.object_id
52 }
53
54 pub fn type_name(&self) -> &'static str {
56 match self.object_id {
57 PcbObjectId::Arc => "Arc",
58 PcbObjectId::Pad => "Pad",
59 PcbObjectId::Via => "Via",
60 PcbObjectId::Track => "Track",
61 PcbObjectId::Text => "Text",
62 PcbObjectId::Fill => "Fill",
63 PcbObjectId::Region => "Region",
64 PcbObjectId::ComponentBody => "ComponentBody",
65 _ => "Unknown",
66 }
67 }
68
69 pub fn raw_data(&self) -> &[u8] {
71 &self.raw_data
72 }
73
74 pub fn has_fields(&self) -> bool {
76 self.fields.is_some()
77 }
78
79 pub fn get(&self, key: &str) -> Option<&Value> {
81 self.fields.as_ref()?.get(&key.to_uppercase())
82 }
83
84 pub fn get_int(&self, key: &str) -> Option<i64> {
86 self.get(key).and_then(|v| v.as_int())
87 }
88
89 pub fn get_float(&self, key: &str) -> Option<f64> {
91 self.get(key).and_then(|v| v.as_float())
92 }
93
94 pub fn get_coord(&self, key: &str) -> Option<crate::types::Coord> {
96 self.get(key).and_then(|v| v.as_coord())
97 }
98
99 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
101 self.fields
102 .iter()
103 .flat_map(|f| f.iter())
104 .map(|(k, v)| (k.as_str(), v))
105 }
106
107 pub fn is_modified(&self) -> bool {
109 self.modified
110 }
111
112 pub fn set(&mut self, key: &str, value: impl Into<Value>) {
114 let fields = self.fields.get_or_insert_with(IndexMap::new);
115 fields.insert(key.to_uppercase(), value.into());
116 self.modified = true;
117 }
118
119 pub fn to_binary(&self) -> Vec<u8> {
125 self.raw_data.clone()
128 }
129
130 pub fn size(&self) -> usize {
132 self.raw_data.len()
133 }
134}
135
136impl Default for BinaryRecord {
137 fn default() -> Self {
138 BinaryRecord {
139 object_id: PcbObjectId::None,
140 raw_data: Vec::new(),
141 fields: None,
142 modified: false,
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_from_binary() {
153 let data = vec![0x01, 0x02, 0x03, 0x04];
154 let record = BinaryRecord::from_binary(PcbObjectId::Track, data.clone());
155
156 assert_eq!(record.object_id(), PcbObjectId::Track);
157 assert_eq!(record.raw_data(), &data);
158 assert!(!record.has_fields());
159 }
160
161 #[test]
162 fn test_with_fields() {
163 let mut fields = IndexMap::new();
164 fields.insert("WIDTH".to_string(), Value::Int(1000));
165
166 let record = BinaryRecord::from_binary_with_fields(PcbObjectId::Track, vec![], fields);
167
168 assert!(record.has_fields());
169 assert_eq!(record.get_int("WIDTH"), Some(1000));
170 }
171
172 #[test]
173 fn test_modification() {
174 let mut record = BinaryRecord::from_binary(PcbObjectId::Track, vec![]);
175 assert!(!record.is_modified());
176
177 record.set("WIDTH", 2000i64);
178 assert!(record.is_modified());
179 }
180}