notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

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 }