1use std::slice;
5
6use nifty_download::{StatePlace, StateReader};
7use nifty_runtime::{Failure, Step};
8
9use crate::context::Context;
10use crate::value::{self, Slot, TypeDesc};
11
12#[derive(Clone, Debug, PartialEq, Eq)]
15pub(crate) struct Location {
16 state: usize,
17 path: Vec<Step>,
18}
19
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21#[repr(u8)]
22pub enum StepKind {
23 Field,
24 Index,
25}
26
27#[derive(Clone, Copy, Debug)]
29#[repr(C)]
30pub struct PathStep {
31 pub kind: StepKind,
32 pub index: i64,
33}
34
35#[derive(Debug)]
38#[repr(C)]
39pub struct PlaceDesc {
40 pub state: u32,
41 pub steps: *const PathStep,
42 pub len: usize,
43}
44
45impl Location {
46 pub(crate) unsafe fn from_place(place: &PlaceDesc) -> Result<Self, Failure> {
49 let steps = if place.len == 0 {
50 &[]
51 } else {
52 unsafe { slice::from_raw_parts(place.steps, place.len) }
54 };
55 let path = steps
56 .iter()
57 .map(|step| {
58 let index = usize::try_from(step.index)
59 .map_err(|_| Failure::NegativePosition(step.index))?;
60 Ok(match step.kind {
61 StepKind::Field => Step::Field(index),
62 StepKind::Index => Step::Index(index),
63 })
64 })
65 .collect::<Result<_, _>>()?;
66 Ok(Self {
67 state: place.state as usize,
68 path,
69 })
70 }
71}
72
73impl StatePlace for Location {
74 fn steps(&self) -> &[Step] {
75 &self.path
76 }
77
78 fn with_steps(&self, steps: Vec<Step>) -> Self {
79 Self {
80 state: self.state,
81 path: steps,
82 }
83 }
84
85 fn same_root(&self, other: &Self) -> bool {
86 self.state == other.state
87 }
88}
89
90pub(crate) struct StateOf<'a>(pub &'a Context);
94
95impl StateReader for StateOf<'_> {
96 type Place = Location;
97
98 fn list_len(&self, place: &Location) -> Option<usize> {
99 Some(value::as_list(self.0.read_location(place)?).items.len())
100 }
101
102 fn holds_text(&self, place: &Location, text: &str) -> bool {
103 self.0
104 .read_location(place)
105 .is_some_and(|slot| value::as_str(slot) == text)
106 }
107}
108
109impl Context {
110 fn read_location(&self, location: &Location) -> Option<Slot> {
112 let mut slot = self.state(location.state);
113 for step in &location.path {
114 slot = match *step {
115 Step::Field(index) => value::as_struct(slot).fields[index],
116 Step::Index(position) => *value::as_list(slot).items.get(position)?,
117 };
118 }
119 Some(slot)
120 }
121
122 pub(crate) fn write_location(
125 &self,
126 location: &Location,
127 value: Slot,
128 ty: &TypeDesc,
129 ) -> Result<(), Failure> {
130 let mut slot = unsafe { &mut *self.state_mut(location.state) };
133 for step in &location.path {
134 slot = match *step {
135 Step::Field(index) => &mut value::struct_mut(slot).fields[index],
136 Step::Index(position) => {
137 let items = &mut value::list_mut(slot).items;
138 let len = items.len();
139 let Some(item) = items.get_mut(position) else {
140 value::release(value, ty);
141 return Err(Failure::NoItem { position, len });
142 };
143 item
144 }
145 };
146 }
147 value::release(std::mem::replace(slot, value), ty);
148 Ok(())
149 }
150}