blockworx_store/
worked.rs1use blockworx_doc::block_model::{Area, Block, Image, Pin, Route, RouteLabel, Text};
12use blockworx_doc::commit::Commit;
13use blockworx_doc::document::Document;
14use blockworx_doc::id::{
15 AreaId, BlockId, EntityRef, ImageId, PinId, RouteId, RouteLabelId, TextId,
16};
17use blockworx_doc::opcode::OpCodes;
18
19#[derive(Clone, Debug, PartialEq)]
26pub struct Worked {
27 pub scope: BlockId,
28 pub touched: Vec<EntityRef>,
29}
30
31impl Worked {
32 pub fn nothing() -> Self {
35 Self {
36 scope: BlockId::NULL,
37 touched: Vec::new(),
38 }
39 }
40
41 pub fn recorded(row: &crate::manifest::Row) -> Self {
44 Self {
45 scope: row.scope.innermost().unwrap_or(BlockId::NULL),
46 touched: row.touched.clone(),
47 }
48 }
49
50 pub fn of(document: &Document, commit: &Commit) -> Self {
53 let mut touched: Vec<EntityRef> = Vec::new();
54 for target in commit.ops().iter().map(OpCodes::target) {
55 if !touched.contains(&target) {
56 touched.push(target);
57 }
58 }
59 let scope = touched
60 .iter()
61 .find_map(|subject| {
62 scope_of(
63 Step {
64 before: document,
65 after: document,
66 },
67 *subject,
68 )
69 })
70 .unwrap_or(BlockId::NULL);
71 Self { scope, touched }
72 }
73}
74
75#[derive(Clone, Copy)]
82pub struct Step<'a> {
83 pub before: &'a Document,
84 pub after: &'a Document,
85}
86
87impl<'a> Step<'a> {
88 pub fn block(self, id: BlockId) -> Option<&'a Block> {
89 self.before.block(&id).or_else(|| self.after.block(&id))
90 }
91 pub fn pin(self, id: PinId) -> Option<&'a Pin> {
92 self.before.pin(&id).or_else(|| self.after.pin(&id))
93 }
94 pub fn route(self, id: RouteId) -> Option<&'a Route> {
95 self.before.route(&id).or_else(|| self.after.route(&id))
96 }
97 pub fn route_label(self, id: RouteLabelId) -> Option<&'a RouteLabel> {
98 self.before
99 .route_label(&id)
100 .or_else(|| self.after.route_label(&id))
101 }
102 pub fn text(self, id: TextId) -> Option<&'a Text> {
103 self.before.text(&id).or_else(|| self.after.text(&id))
104 }
105 pub fn area(self, id: AreaId) -> Option<&'a Area> {
106 self.before.area(&id).or_else(|| self.after.area(&id))
107 }
108 pub fn image(self, id: ImageId) -> Option<&'a Image> {
109 self.before.image(&id).or_else(|| self.after.image(&id))
110 }
111}
112
113pub fn scope_of(step: Step<'_>, subject: EntityRef) -> Option<BlockId> {
118 let inside = container(step, subject)?;
119 Some(match subject {
120 EntityRef::Pin(_) => parent_of(step, inside),
121 _ => inside,
122 })
123}
124
125fn container(step: Step<'_>, subject: EntityRef) -> Option<BlockId> {
129 Some(match subject {
130 EntityRef::Block(id) => step.block(id)?.parent,
131 EntityRef::Area(id) => step.area(id)?.owner,
132 EntityRef::Text(id) => step.text(id)?.owner,
133 EntityRef::Image(id) => step.image(id)?.owner,
134 EntityRef::Route(id) => step.route(id)?.owner,
135 EntityRef::RouteLabel(id) => {
136 let route = step.route_label(id)?.owner;
137 step.route(route)?.owner
138 }
139 EntityRef::Pin(id) => step.pin(id)?.owner,
140 EntityRef::Document | EntityRef::Asset(_) => return None,
141 })
142}
143
144fn parent_of(step: Step<'_>, block: BlockId) -> BlockId {
146 step.block(block)
147 .map_or(BlockId::NULL, |block| block.parent)
148}