Skip to main content

geop_core_program/
reader.rs

1//! [`Reader`]: the only way a part is read — by a make, which records every
2//! read ([`Read`]) on the node it makes, or by an editor, recording
3//! nothing.
4
5use std::{any::TypeId, cell::RefCell, collections::HashSet, rc::Rc};
6
7use geop_core_math::geop_error::{GeopError, GeopResult};
8use serde::{Serialize, de::DeserializeOwned};
9
10use crate::{
11    element::{ElementReference, HasElements, Kind},
12    part::Part,
13    placed::{
14        INSTANCE_SEPARATOR, InInstance, Located, OUTSIDE, PLACED, PlacedPart, key_behind,
15        outermost_instance,
16    },
17    program::Program,
18    runner::{Runner, quoted},
19    target::{Node, Read, TargetReference},
20    values::{Setting, Settings, StateValue, StateValues},
21    workspace::Location,
22};
23
24/// What the node being made has read, in order, each once.
25#[derive(Default)]
26pub(crate) struct Recording {
27    reads: RefCell<Vec<Read>>,
28    keys: RefCell<HashSet<String>>,
29}
30
31impl Recording {
32    fn record(&self, read: Read) {
33        if self.keys.borrow_mut().insert(read.key()) {
34            self.reads.borrow_mut().push(read);
35        }
36    }
37
38    pub(crate) fn take(self) -> Vec<Read> {
39        self.reads.into_inner()
40    }
41}
42
43/// The part as it is before one step, and the only way it is read: by a
44/// make, as of its own step, recording every read so that its node is made
45/// again when any of it changes — or by an editor, recording nothing: the
46/// part now ([`Part::current`]), or before or after one step of the last run
47/// ([`Part::before`], [`Part::after`]), what that step is edited against and
48/// what scrubbing the timeline shows.
49///
50/// A target is read by its elements ([`ElementReference`]), never as a
51/// whole: a target meant to be read whole has a kind of element that is all
52/// of it (see [`HasElements`]).
53///
54/// A part placed in it is read by a reader of its own
55/// ([`Reader::placed_part`]), which records what it reads as read inside
56/// the placed part ([`Read::Inside`]). So is the part it is itself placed
57/// in, while it is built there — the path [`OUTSIDE`], `..`: a step of a
58/// part placed in an assembly reads a part placed beside it there as
59/// `../bracket`, in context.
60#[derive(Clone)]
61pub struct Reader<'a> {
62    part: &'a Part,
63    /// The position of the step it reads before.
64    before: usize,
65    /// The target being made, if it reads for a make: it reads its own
66    /// target as the steps before left it.
67    own: Option<&'a str>,
68    /// What the step being run made of the target being made last: what a
69    /// placed part is built again from.
70    last: Option<&'a Node>,
71    runner: Option<&'a Runner>,
72    recording: Option<&'a Recording>,
73    /// The path of the part it reads in the part of the node being made:
74    /// empty for that part itself.
75    path: Vec<String>,
76    /// The part the part it reads is placed in, as the step placing it
77    /// reads it, while it is built there: what `..` reads. None for a part
78    /// built on its own, and for a part placed in the part read.
79    outside: Option<Rc<Reader<'a>>>,
80    /// The state it reads in place of its part's, where that gives a value
81    /// — a state a solve tries ([`Reader::trying`]) — by the names of the
82    /// part it was given for, and the path of the part it reads in that
83    /// part.
84    trying: Option<(&'a StateValues, String)>,
85}
86
87impl<'a> Reader<'a> {
88    /// The part `part` before the step at position `before`, recording
89    /// nothing.
90    pub(crate) fn new(part: &'a Part, before: usize) -> Self {
91        Self {
92            part,
93            before,
94            own: None,
95            last: None,
96            runner: None,
97            recording: None,
98            path: Vec::new(),
99            outside: None,
100            trying: None,
101        }
102    }
103
104    /// It as if its part were run at the state `state`, where that gives a
105    /// value — `/bolt:b.pose` the state `b.pose` of the part placed as
106    /// `bolt` — every target as its part built it: what a solve reads at
107    /// every state it tries, without running the program again.
108    ///
109    /// Only for what reads no target that itself read the state, which
110    /// would be as built at the part's own: a constraint's make, which
111    /// refuses any such read (see [`Reader::targets_reading_state`]).
112    pub fn trying(&self, state: &'a StateValues) -> Reader<'a> {
113        Reader {
114            trying: Some((state, String::new())),
115            ..self.clone()
116        }
117    }
118
119    /// The same part after the step `step` of its last run, with what that
120    /// step produced: what the step's make read, as of the end of the
121    /// step. The finished part for a step that did not run.
122    pub fn after_step(&self, step: &str) -> Reader<'a> {
123        Reader {
124            before: (self.part.position(step)).map_or(self.part.ran(), |at| at + 1),
125            own: None,
126            last: None,
127            ..self.clone()
128        }
129    }
130
131    /// The reader of the make of `own`, by the step at position `before`,
132    /// recording into `recording`. `last` is what the step made of it last;
133    /// `outside`, the part the part is placed in, if it is built placed.
134    pub(crate) fn making(
135        part: &'a Part,
136        before: usize,
137        own: &'a str,
138        last: Option<&'a Node>,
139        runner: &'a Runner,
140        recording: &'a Recording,
141        outside: Option<Rc<Reader<'a>>>,
142    ) -> Self {
143        Self {
144            part,
145            before,
146            own: Some(own),
147            last,
148            runner: Some(runner),
149            recording: Some(recording),
150            path: Vec::new(),
151            outside,
152            trying: None,
153        }
154    }
155
156    /// Records `read`, if it records: as read inside the part it reads.
157    fn record(&self, read: Read) {
158        if let Some(recording) = self.recording {
159            let read = (self.path.iter().rev()).fold(read, |read, instance| Read::Inside {
160                instance: instance.clone(),
161                read: Box::new(read),
162            });
163            recording.record(read);
164        }
165    }
166
167    /// The part it reads, and the target being made in it, if any.
168    pub(crate) fn part(&self) -> &'a Part {
169        self.part
170    }
171
172    /// The position of the step it reads before.
173    pub(crate) fn position(&self) -> usize {
174        self.before
175    }
176
177    /// What tells the part it reads from another ([`Seen`]): equal for two
178    /// readers exactly when they see the same values — of one part or of
179    /// two — so a view drawn of one is a view of the other: what an editor
180    /// sends a viewer again only when it changed.
181    pub fn seen(&self) -> Seen {
182        Seen {
183            versions: self.part.versions(self.before, self.own),
184            inputs: self.part.inputs.clone(),
185            state: self.part.state.clone(),
186        }
187    }
188
189    /// What `read` makes of the part it reads, and what of the part it read
190    /// to make it: equal reads ([`Reader::reads_same`]) make it alike, so
191    /// what an editor draws of a part is kept by what each drawer read,
192    /// and drawn again only when that changed.
193    pub fn recorded<T>(&self, read: impl FnOnce(&Reader) -> T) -> (T, Reads) {
194        let recording = Recording::default();
195        let reader = Reader {
196            recording: Some(&recording),
197            path: Vec::new(),
198            ..self.clone()
199        };
200        let made = read(&reader);
201        (made, Reads(recording.take()))
202    }
203
204    /// Whether everything `reads` read ([`Reader::recorded`]) reads the
205    /// same through it.
206    pub fn reads_same(&self, reads: &Reads) -> bool {
207        (reads.0.iter()).all(|read| {
208            (self.part).holds(
209                read,
210                self.before,
211                self.own,
212                self.runner,
213                self.outside_reader(),
214            )
215        })
216    }
217
218    /// The target being made, if it reads for a make of its own part.
219    pub(crate) fn own(&self) -> Option<&'a str> {
220        self.own
221    }
222
223    /// The same, as of the make of `own`, recording nothing: what reads a
224    /// placed part's step, `placed:<instance>`, as its make did.
225    pub(crate) fn for_make_of(mut self, own: &'a str) -> Self {
226        self.own = Some(own);
227        self
228    }
229
230    /// What the step being run made of the target being made last.
231    pub(crate) fn last(&self) -> Option<&'a Node> {
232        self.last
233    }
234
235    /// The part the part it reads is placed in, while it is built there.
236    pub(crate) fn outside_reader(&self) -> Option<&Reader<'a>> {
237        self.outside.as_deref()
238    }
239
240    /// The same, of a part placed in the part `outside` reads — as the
241    /// step placing it reads that part ([`Part::placing`]): what it reads
242    /// in context, through `..`, is read there. What an editor edits a step
243    /// of a placed part against, where it is placed.
244    pub fn placed_in(mut self, outside: Reader<'a>) -> Self {
245        self.outside = Some(Rc::new(outside));
246        self
247    }
248
249    /// The runner of the step being run: an error for a reader of an
250    /// editor, which runs nothing.
251    pub(crate) fn runner(&self) -> GeopResult<&'a Runner> {
252        self.runner
253            .ok_or_else(|| GeopError::new("only a make reads files and places parts"))
254    }
255
256    /// Records the read of `read` as such, unchanged: what a placed part
257    /// passes up of what it read.
258    pub(crate) fn record_raw(&self, read: Read) {
259        self.record(read);
260    }
261
262    /// Changes exactly when a run changes any node of the part it reads
263    /// (see [`Part::revision`]).
264    pub fn revision(&self) -> u64 {
265        self.part.revision()
266    }
267
268    /// The node of `name` it sees, the read recorded, or why there is none.
269    fn node(&self, name: &str) -> GeopResult<&'a Node> {
270        match self.part.visible(name, self.before, self.own) {
271            Some((_, node)) => {
272                self.record(Read::Target {
273                    name: name.to_string(),
274                    producer: node.step.clone(),
275                    version: node.version,
276                });
277                Ok(node)
278            }
279            None => {
280                self.record(Read::Absent(name.to_string()));
281                let seen: Vec<String> = (self.part.versions(self.before, self.own).into_iter())
282                    .map(|(seen, _)| format!("`{seen}`"))
283                    .collect();
284                let seen = match seen.is_empty() {
285                    true => "none".to_string(),
286                    false => seen.join(", "),
287                };
288                let suppressed = self.part.suppressed_before(self.before);
289                let suppressed = match suppressed.is_empty() {
290                    true => String::new(),
291                    false => format!("; suppressed before here: {}", quoted(&suppressed)),
292                };
293                Err(GeopError::new(format!(
294                    "no step before here produces target `{name}` (the targets before here: \
295                     {seen}{suppressed})"
296                )))
297            }
298        }
299    }
300
301    /// The target `reference`, whole, the read recorded.
302    pub(crate) fn target<T: 'static>(&self, reference: &TargetReference<T>) -> GeopResult<&'a T> {
303        let name = reference.name();
304        self.node(name)?.get(name)
305    }
306
307    /// A copy of the target being made as the steps before left it: what a
308    /// chain target ([`crate::target::Target::CHAIN`]) is produced from —
309    /// the default, if no step produced it before. The read is recorded.
310    pub fn previous<T: Clone + Default + 'static>(&self) -> GeopResult<T> {
311        let own = self
312            .own
313            .filter(|_| self.path.is_empty())
314            .ok_or_else(|| GeopError::new("only a target being made has a previous version"))?;
315        if self.part.visible(own, self.before, self.own).is_none() {
316            self.record(Read::Absent(own.to_string()));
317            return Ok(T::default());
318        }
319        self.target(&TargetReference::<T>::new(own)).cloned()
320    }
321
322    /// The element `reference` names, of the part itself. One of a part
323    /// placed in it is an error naming the instance: it is where that
324    /// instance is, which [`Reader::retrieve_placed`] says.
325    pub fn retrieve_element<T: HasElements<K>, K: Kind>(
326        &self,
327        reference: &ElementReference<T, K>,
328    ) -> GeopResult<T::Element<'a>> {
329        let placed = self.retrieve_placed(reference)?;
330        match placed.instance.is_empty() {
331            true => Ok(placed.element),
332            false => Err(GeopError::new(format!(
333                "{reference:?} is of the placed part `{}`: this takes elements of the part itself",
334                placed.instance
335            ))),
336        }
337    }
338
339    /// The element `reference` names, of the part itself or of a part
340    /// placed in it — however deep — as it is in its own part, with the
341    /// instance's path: where that is placed, the step that placed it
342    /// says. The read is recorded inside the placed part.
343    pub fn retrieve_placed<T: HasElements<K>, K: Kind>(
344        &self,
345        reference: &ElementReference<T, K>,
346    ) -> GeopResult<InInstance<T::Element<'a>>> {
347        let (path, target) = (reference.instance(), reference.target().name());
348        let resolve = |reader: &Reader<'a>| {
349            let value = match (
350                reader.part.visible(target, reader.before, reader.own),
351                T::undefined(),
352            ) {
353                (None, Some(undefined)) => {
354                    reader.record(Read::Absent(target.to_string()));
355                    undefined
356                }
357                _ => reader.target(&TargetReference::<T>::new(target))?,
358            };
359            value.element(reference.name())
360        };
361        let element = match path.is_empty() {
362            true => resolve(self),
363            false => self.placed_part(path).and_then(|inside| resolve(&inside)),
364        };
365        let element = element.map_err(|e| e.with_context(format!("resolving {reference:?}")))?;
366        Ok(InInstance {
367            element,
368            instance: path.to_string(),
369        })
370    }
371
372    /// The part placed at `path` — `bolt`, or `asm/bolt` — as it was built,
373    /// every read of it recorded as read inside it. `..` ([`OUTSIDE`]) is
374    /// the part it is placed in — `../bracket` a part placed beside it —
375    /// as the step placing it sees that part: only parts placed before it,
376    /// so that no two parts read each other.
377    pub fn placed_part(&self, path: &str) -> GeopResult<Reader<'a>> {
378        let ctx = |e: GeopError| e.with_context(format!("the placed part {path:?}"));
379        let mut level = self.clone();
380        for name in path.split(INSTANCE_SEPARATOR) {
381            if name == OUTSIDE {
382                level = level.outside().map_err(ctx)?.0;
383                continue;
384            }
385            let inner = level.part.placed_at(name, level.before, level.own);
386            let inner = match (inner, level.path.last()) {
387                (Ok(inner), _) => inner,
388                (Err(e), Some(last)) if last == OUTSIDE => {
389                    let me = (level.own.and_then(|own| own.strip_prefix(PLACED))).unwrap_or("");
390                    return Err(ctx(e.with_context(format!(
391                        "`{me}` reads `{name}` placed beside it in context: a part reads only \
392                         the parts placed before it, so that no two parts read each other, \
393                         and `{name}` is placed after `{me}`, or not at all"
394                    ))));
395                }
396                (Err(e), _) => return Err(ctx(e)),
397            };
398            let mut inside = Reader::new(inner, inner.ran());
399            inside.runner = level.runner;
400            inside.recording = level.recording;
401            inside.path = level.path.clone();
402            inside.path.push(name.to_string());
403            inside.trying = (level.trying.as_ref())
404                .map(|(state, at)| (*state, crate::placed::instance_path(at, name)));
405            level = inside;
406        }
407        Ok(level)
408    }
409
410    /// The part the part it reads is placed in, as the step placing it
411    /// reads it — every read of it recorded as read there, through `..` —
412    /// and the instance that step places it as. An error for a part built
413    /// on its own, which no part places.
414    pub fn outside(&self) -> GeopResult<(Reader<'a>, &'a str)> {
415        let outside = self.outside.as_deref().ok_or_else(|| {
416            GeopError::new(format!(
417                "`{OUTSIDE}` is the part this one is placed in, read in context: this one is \
418                 built on its own, placed in none — open the part that places it"
419            ))
420        })?;
421        let me = (outside.own.and_then(|own| own.strip_prefix(PLACED)))
422            .ok_or_else(|| GeopError::new("the part this one is placed in places no part here"))?;
423        let mut level = outside.clone();
424        level.recording = self.recording;
425        level.runner = self.runner.or(outside.runner);
426        level.path = self.path.clone();
427        level.path.push(OUTSIDE.to_string());
428        Ok((level, me))
429    }
430
431    /// The name of every part placed in the part it reads — not in those —
432    /// in the order the steps placed them. The listing is recorded.
433    pub fn instances(&self) -> Vec<&'a str> {
434        (self.listed::<PlacedPart>().into_iter())
435            .filter(|(_, node)| node.value.is_ok())
436            .filter_map(|(name, _)| name.strip_prefix(PLACED))
437            .collect()
438    }
439
440    /// The input's value, if the run gives one, the read recorded. An input
441    /// behind an instance's path — `/bolt:d` — is read inside the placed
442    /// part.
443    pub fn retrieve_input(&self, name: &str) -> Option<Setting> {
444        if let Some((instance, inside)) = outermost_instance(name) {
445            return self.placed_part(instance).ok()?.retrieve_input(inside);
446        }
447        let value = self.part.inputs.get(name).cloned();
448        self.record(Read::Input(name.to_string(), value.clone()));
449        value
450    }
451
452    /// The state's value; the default if the run gives none.
453    pub fn retrieve_state(&self, name: &str) -> StateValue {
454        self.given_state(name).unwrap_or_default()
455    }
456
457    /// The state's value, if the run gives one, the read recorded. A state
458    /// behind an instance's path — `/bolt:b.pose` — is the part's own value
459    /// of that name where it gives one: the value the placed part is built
460    /// with. Else it is read inside the placed part — the placed program's
461    /// own, or none before a step placed it.
462    pub fn given_state(&self, name: &str) -> Option<StateValue> {
463        let value = self.own_state(name);
464        self.record(Read::State(name.to_string(), value.clone()));
465        match (value, outermost_instance(name)) {
466            (Some(value), _) => Some(value),
467            (None, None) => None,
468            (None, Some((instance, inside))) => {
469                self.placed_part(instance).ok()?.given_state(inside)
470            }
471        }
472    }
473
474    /// The value of the state `name` its part has itself — at the state it
475    /// tries, where that gives one ([`Reader::trying`]): what
476    /// [`Reader::given_state`] reads first, and records.
477    fn own_state(&self, name: &str) -> Option<StateValue> {
478        let tried = (self.trying.as_ref()).and_then(|(state, at)| match at.is_empty() {
479            true => state.get(name),
480            false => state.get(&key_behind(at, name)),
481        });
482        tried.or_else(|| self.part.state.get(name)).cloned()
483    }
484
485    /// Whether every state `reads` read ([`Reader::recorded`]) reads the
486    /// same through it — at the state it tries, if it tries one — in its
487    /// part and in the parts placed in it. Only the state: of the same
488    /// part, built once, as a solve reads it at every state it tries,
489    /// nothing else read can have changed.
490    pub fn reads_same_state(&self, reads: &Reads) -> bool {
491        (reads.0.iter()).all(|read| self.state_holds(read))
492    }
493
494    /// Whether `read`, if of a state, reads the same through it.
495    fn state_holds(&self, read: &Read) -> bool {
496        match read {
497            Read::State(name, value) => self.own_state(name) == *value,
498            Read::Inside { instance, read } => {
499                (self.placed_part(instance)).is_ok_and(|inside| inside.state_holds(read))
500            }
501            _ => true,
502        }
503    }
504
505    /// Whether it has read the state `name`: what a check of a value read
506    /// from the state, a constraint's derivatives, asks.
507    pub fn has_read_state(&self, name: &str) -> bool {
508        (self.recording).is_some_and(|recording| {
509            let read = Read::State(name.to_string(), None);
510            let key = (self.path.iter().rev())
511                .fold(read.key(), |key, instance| key_behind(instance, &key));
512            recording.has(&key)
513        })
514    }
515
516    /// Every target the make it reads for read so far that itself read a
517    /// state, directly or through what it read, with that state: what
518    /// moves with the state without the make's derivatives seeing it.
519    pub fn targets_reading_state(&self) -> Vec<(Located, String)> {
520        let Some(recording) = self.recording else {
521            return Vec::new();
522        };
523        let reads = recording.reads.borrow();
524        (reads.iter())
525            .filter(|read| !matches!(innermost(read), Read::State(..)))
526            .filter_map(|read| {
527                let state = self.part.state_read(read, self.before, self.own)?;
528                Some((target_of(read), state))
529            })
530            .collect()
531    }
532
533    /// Whether a step before it produced `reference`, made or failed, the
534    /// read recorded: what tells a target no step produced, which a
535    /// collection reads as empty, from one that failed.
536    pub fn defines<T>(&self, reference: &TargetReference<T>) -> bool {
537        self.node(reference.name()).is_ok()
538    }
539
540    /// Every target it sees whose value is a `T`, in the order the steps
541    /// produced them — of one step, by name: the sketches a step could
542    /// pick, say, the newest last. Which there are is recorded.
543    pub fn targets_of<T: 'static>(&self) -> Vec<TargetReference<T>> {
544        (self.listed::<T>().into_iter())
545            .filter(|(_, node)| node.value.is_ok())
546            .map(|(name, _)| TargetReference::new(name))
547            .collect()
548    }
549
550    /// Why every target it sees that is produced to hold a `T` but failed
551    /// did, in the order the steps produced them: what a question over all
552    /// of them — every constraint of a part — cannot be answered without.
553    pub fn failed_targets_of<T: 'static>(&self) -> Vec<GeopError> {
554        (self.listed::<T>().into_iter())
555            .filter_map(|(name, node)| {
556                self.record(Read::Target {
557                    name: name.to_string(),
558                    producer: node.step.clone(),
559                    version: node.version,
560                });
561                node.failure(name)
562            })
563            .collect()
564    }
565
566    /// Every target produced to hold a `T` it sees, the listing recorded.
567    fn listed<T: 'static>(&self) -> Vec<(&'a str, &'a Node)> {
568        let listed = self.part.listed(TypeId::of::<T>(), self.before, self.own);
569        self.record(Read::Listed {
570            kind: std::any::type_name::<T>().into(),
571            targets: (listed.iter())
572                .map(|(name, node)| (name.to_string(), node.step.clone()))
573                .collect(),
574        });
575        listed
576    }
577
578    /// The text of the file the program of the step being run names
579    /// `name`, and its path. The read is recorded.
580    pub fn read_file(&self, name: &str) -> GeopResult<(String, Rc<str>)> {
581        let runner = self.runner()?;
582        let (path, text) = runner.read(name)?;
583        self.record(Read::File(path.clone(), runner.revision(&path)));
584        Ok((path, text))
585    }
586
587    /// The bytes of the file the program of the step being run names
588    /// `name`, and its path. The read is recorded.
589    pub fn read_bytes(&self, name: &str) -> GeopResult<(String, Rc<[u8]>)> {
590        let runner = self.runner()?;
591        let (path, bytes) = runner.read_bytes(name)?;
592        self.record(Read::File(path.clone(), runner.revision(&path)));
593        Ok((path, bytes))
594    }
595
596    /// What the file the program of the step being run names `name` reads
597    /// as, as `kind` — a STEP file's bodies — made of its text by `make`,
598    /// and its path: made once for every build its workspace's cache keeps
599    /// it for (see [`crate::cache`]). The read is recorded.
600    pub fn read_file_as<T: Serialize + DeserializeOwned + 'static>(
601        &self,
602        name: &str,
603        kind: &'static str,
604        make: impl FnOnce(&str) -> GeopResult<T>,
605    ) -> GeopResult<(String, Rc<T>)> {
606        let (path, text) = self.read_file(name)?;
607        let cache = (self.runner()?.workspace.as_deref()).and_then(|workspace| workspace.cache());
608        let value = match cache {
609            Some(cache) => cache.made_of(kind, &path, &text, make)?,
610            None => Rc::new(make(&text)?),
611        };
612        Ok((path, value))
613    }
614
615    /// The program in the file the program of the step being run names
616    /// `name`, and where it would be placed from there (see
617    /// [`Runner::program`]). The read is recorded.
618    pub fn program(&self, name: &str) -> GeopResult<(Rc<Program>, Location)> {
619        let runner = self.runner()?;
620        let (program, location) = runner.program(name)?;
621        self.record(Read::File(
622            location.file.clone(),
623            runner.revision(&location.file),
624        ));
625        Ok((program, location))
626    }
627}
628
629/// What a reader read of its part ([`Reader::recorded`]), each thing once.
630#[derive(Clone, Default)]
631pub struct Reads(pub(crate) Vec<Read>);
632
633/// Everything a [`Reader`] reads from ([`Reader::seen`]): the version of
634/// every target it sees, by name, and the inputs and the state its part
635/// was run with — which a placed part's pose is read from, not built into
636/// its node, so that moving a part builds nothing.
637#[derive(Clone, Debug, PartialEq)]
638pub struct Seen {
639    pub versions: Vec<(String, u64)>,
640    pub inputs: Settings,
641    pub state: StateValues,
642}
643
644/// What `read` read, inside the placed parts it went into.
645fn innermost(read: &Read) -> &Read {
646    match read {
647        Read::Inside { read, .. } => innermost(read),
648        read => read,
649    }
650}
651
652/// The name of the target `read` read, behind the path of the placed part
653/// it is in.
654fn target_of(read: &Read) -> Located {
655    match read {
656        Read::Target { name, .. } | Read::Absent(name) | Read::Input(name, _) => Located::new(name),
657        Read::State(name, _) | Read::File(name, _) => Located::new(name),
658        Read::Listed { .. } => Located::default(),
659        Read::Inside { instance, read } => target_of(read).behind(instance),
660    }
661}
662
663impl Recording {
664    fn has(&self, key: &str) -> bool {
665        self.keys.borrow().contains(key)
666    }
667}