ast.rs (7685B)
1 use std::fmt; 2 3 /// Index into Space.cells 4 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 5 pub struct CellId(pub u32); 6 7 /// The parsed space — a flat arena of cells and attributes. 8 /// 9 /// Cells and attributes are stored contiguously. Each cell references 10 /// its attributes via a range into `attributes`, and its children 11 /// via a range into `child_ids` (which itself stores CellIds). 12 pub struct Space { 13 /// All cells, indexed by CellId 14 pub cells: Vec<Cell>, 15 /// All attributes, contiguous per cell 16 pub attributes: Vec<Attribute>, 17 /// Flat child reference array — cells index into this 18 pub child_ids: Vec<CellId>, 19 /// Root cell of the space 20 pub root: CellId, 21 } 22 23 pub struct Cell { 24 pub cell_type: CellType, 25 /// Index of first attribute in Space.attributes 26 pub first_attr: u32, 27 /// Number of attributes 28 pub attr_count: u16, 29 /// Index of first child reference in Space.child_ids 30 pub first_child: u32, 31 /// Number of children 32 pub child_count: u16, 33 /// Parent cell 34 pub parent: Option<CellId>, 35 } 36 37 #[derive(Clone, Debug, PartialEq)] 38 pub enum CellType { 39 Room, 40 Space, 41 Group, 42 Tilemap, 43 Object(ObjectType), 44 } 45 46 #[derive(Clone, Debug, PartialEq)] 47 pub enum ObjectType { 48 Table, 49 Chair, 50 Door, 51 Light, 52 Custom(String), 53 } 54 55 #[derive(Clone, Debug, PartialEq)] 56 pub enum Attribute { 57 Id(String), 58 Type(String), 59 Name(String), 60 Material(String), 61 Condition(String), 62 Shape(Shape), 63 Width(f64), 64 Depth(f64), 65 Height(f64), 66 Location(Location), 67 State(CellState), 68 Position(f64, f64, f64), 69 /// Euler rotation in degrees (X, Y, Z), applied in YXZ order. 70 Rotation(f64, f64, f64), 71 ModelUrl(String), 72 /// Tilemap tile type names, e.g. ["grass", "stone", "water"]. 73 Tileset(Vec<String>), 74 /// Compact tile data string, e.g. "0" (fill-all) or "0 0 1 1 0 0". 75 Data(String), 76 } 77 78 /// Spatial location relative to the room or another object. 79 #[derive(Clone, Debug, PartialEq)] 80 pub enum Location { 81 /// Center of parent container 82 Center, 83 /// On the floor 84 Floor, 85 /// On the ceiling 86 Ceiling, 87 /// On top of another object (by id) 88 TopOf(String), 89 /// Near another object (by id) 90 Near(String), 91 /// Freeform / unrecognized location value 92 Custom(String), 93 } 94 95 #[derive(Clone, Copy, Debug, PartialEq)] 96 pub enum Shape { 97 Rectangle, 98 Circle, 99 Square, 100 } 101 102 #[derive(Clone, Copy, Debug, PartialEq)] 103 pub enum CellState { 104 On, 105 Off, 106 Sleeping, 107 } 108 109 // --- Display implementations --- 110 111 impl fmt::Display for ObjectType { 112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 113 match self { 114 ObjectType::Table => write!(f, "table"), 115 ObjectType::Chair => write!(f, "chair"), 116 ObjectType::Door => write!(f, "door"), 117 ObjectType::Light => write!(f, "light"), 118 ObjectType::Custom(s) => write!(f, "{}", s), 119 } 120 } 121 } 122 123 impl fmt::Display for CellType { 124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 125 match self { 126 CellType::Room => write!(f, "room"), 127 CellType::Space => write!(f, "space"), 128 CellType::Group => write!(f, "group"), 129 CellType::Tilemap => write!(f, "tilemap"), 130 CellType::Object(o) => write!(f, "{}", o), 131 } 132 } 133 } 134 135 impl fmt::Display for Shape { 136 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 137 match self { 138 Shape::Rectangle => write!(f, "rectangle"), 139 Shape::Circle => write!(f, "circle"), 140 Shape::Square => write!(f, "square"), 141 } 142 } 143 } 144 145 impl fmt::Display for CellState { 146 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 147 match self { 148 CellState::On => write!(f, "on"), 149 CellState::Off => write!(f, "off"), 150 CellState::Sleeping => write!(f, "sleeping"), 151 } 152 } 153 } 154 155 impl fmt::Display for Location { 156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 157 match self { 158 Location::Center => write!(f, "center"), 159 Location::Floor => write!(f, "floor"), 160 Location::Ceiling => write!(f, "ceiling"), 161 Location::TopOf(id) => write!(f, "top-of {}", id), 162 Location::Near(id) => write!(f, "near {}", id), 163 Location::Custom(s) => write!(f, "{}", s), 164 } 165 } 166 } 167 168 // --- Space accessor methods --- 169 170 impl Space { 171 pub fn cell(&self, id: CellId) -> &Cell { 172 &self.cells[id.0 as usize] 173 } 174 175 pub fn children(&self, id: CellId) -> &[CellId] { 176 let cell = self.cell(id); 177 let start = cell.first_child as usize; 178 let end = start + cell.child_count as usize; 179 &self.child_ids[start..end] 180 } 181 182 pub fn attrs(&self, id: CellId) -> &[Attribute] { 183 let cell = self.cell(id); 184 let start = cell.first_attr as usize; 185 let end = start + cell.attr_count as usize; 186 &self.attributes[start..end] 187 } 188 189 pub fn name(&self, id: CellId) -> Option<&str> { 190 self.attrs(id).iter().find_map(|a| match a { 191 Attribute::Name(s) => Some(s.as_str()), 192 _ => None, 193 }) 194 } 195 196 pub fn find_attr<F>(&self, id: CellId, pred: F) -> Option<&Attribute> 197 where 198 F: Fn(&Attribute) -> bool, 199 { 200 self.attrs(id).iter().find(|a| pred(a)) 201 } 202 203 pub fn id_str(&self, id: CellId) -> Option<&str> { 204 self.attrs(id).iter().find_map(|a| match a { 205 Attribute::Id(s) => Some(s.as_str()), 206 _ => None, 207 }) 208 } 209 210 pub fn position(&self, id: CellId) -> Option<(f64, f64, f64)> { 211 self.attrs(id).iter().find_map(|a| match a { 212 Attribute::Position(x, y, z) => Some((*x, *y, *z)), 213 _ => None, 214 }) 215 } 216 217 /// Euler rotation in degrees (X, Y, Z). 218 pub fn rotation(&self, id: CellId) -> Option<(f64, f64, f64)> { 219 self.attrs(id).iter().find_map(|a| match a { 220 Attribute::Rotation(x, y, z) => Some((*x, *y, *z)), 221 _ => None, 222 }) 223 } 224 225 pub fn model_url(&self, id: CellId) -> Option<&str> { 226 self.attrs(id).iter().find_map(|a| match a { 227 Attribute::ModelUrl(s) => Some(s.as_str()), 228 _ => None, 229 }) 230 } 231 232 pub fn location(&self, id: CellId) -> Option<&Location> { 233 self.attrs(id).iter().find_map(|a| match a { 234 Attribute::Location(loc) => Some(loc), 235 _ => None, 236 }) 237 } 238 239 pub fn width(&self, id: CellId) -> Option<f64> { 240 self.attrs(id).iter().find_map(|a| match a { 241 Attribute::Width(n) => Some(*n), 242 _ => None, 243 }) 244 } 245 246 pub fn height(&self, id: CellId) -> Option<f64> { 247 self.attrs(id).iter().find_map(|a| match a { 248 Attribute::Height(n) => Some(*n), 249 _ => None, 250 }) 251 } 252 253 pub fn depth(&self, id: CellId) -> Option<f64> { 254 self.attrs(id).iter().find_map(|a| match a { 255 Attribute::Depth(n) => Some(*n), 256 _ => None, 257 }) 258 } 259 260 pub fn shape(&self, id: CellId) -> Option<&Shape> { 261 self.attrs(id).iter().find_map(|a| match a { 262 Attribute::Shape(s) => Some(s), 263 _ => None, 264 }) 265 } 266 267 pub fn tileset(&self, id: CellId) -> Option<&Vec<String>> { 268 self.attrs(id).iter().find_map(|a| match a { 269 Attribute::Tileset(v) => Some(v), 270 _ => None, 271 }) 272 } 273 274 pub fn data(&self, id: CellId) -> Option<&str> { 275 self.attrs(id).iter().find_map(|a| match a { 276 Attribute::Data(s) => Some(s.as_str()), 277 _ => None, 278 }) 279 } 280 }