pub struct Selection<'a> { /* private fields */ }Implementations§
Source§impl<'a> Selection<'a>
impl<'a> Selection<'a>
pub fn input(&self) -> &'a Input
Sourcepub fn items(&self) -> &[SelectedItem<'a>]
pub fn items(&self) -> &[SelectedItem<'a>]
Examples found in repository?
examples/grow-wedding.rs (line 90)
63fn grow(bytes: Vec<u8>, factor: usize) -> Result<Vec<u8>> {
64 if !(1..=MAX_FACTOR).contains(&factor) {
65 return Err(format!("FACTOR must be in 1..={MAX_FACTOR}"));
66 }
67 if bytes.len() > MAX_INPUT {
68 return Err("input exceeds 1 MiB".into());
69 }
70 let input = Input::parse_named(bytes, FileMode::Data, "wedding.dzn")
71 .map_err(|error| format!("invalid data: {error:?}"))?;
72 if input
73 .syntax()
74 .tokens()
75 .len()
76 .checked_mul(factor)
77 .is_none_or(|n| n > MAX_TOKENS)
78 {
79 return Err("grown input exceeds the 200,000-token allowance".into());
80 }
81 // This example understands these eight assignments, not arbitrary dependencies.
82 let QueryResult::Selection(items) = Query::parse("items", Limits::default())
83 .map_err(|error| error.message)?
84 .evaluate(&input, Limits::default())
85 .map_err(|error| error.message)?
86 else {
87 unreachable!()
88 };
89 let mut names = BTreeSet::new();
90 for item in items.items() {
91 if item.kind != ItemKind::Assignment
92 || !item
93 .name
94 .is_some_and(|name| ASSIGNMENTS.contains(&name) && names.insert(name))
95 {
96 return Err("expected only the eight distinct wedding data assignments".into());
97 }
98 }
99 if names.len() != ASSIGNMENTS.len() {
100 return Err("all eight wedding data assignments are required".into());
101 }
102 // Refuse formatter directives: copying their text could change directive scopes.
103 for (index, token) in input.syntax().tokens().iter().enumerate() {
104 if matches!(token.kind, TokenKind::LineComment | TokenKind::BlockComment)
105 && input
106 .token_bytes(index)
107 .windows(b"zincite-fmt:".len())
108 .any(|w| w == b"zincite-fmt:")
109 {
110 return Err("comments containing zincite directives are unsupported".into());
111 }
112 }
113 let topics = literal(&input, "Topics")?;
114 let guests = literal(&input, "Guests")?;
115 let records = literal(&input, "guests")?;
116 let same = literal(&input, "same_table")?;
117 let different = literal(&input, "different_tables")?;
118 let capacities = literal(&input, "table_capacities")?;
119 let imbalance = literal(&input, "max_gender_imbalance_per_table")?;
120 let topic_members = members(&topics)?;
121 let guest_members = members(&guests)?;
122 if topic_members.is_empty() || guest_members.is_empty() {
123 return Err("Topics and Guests must be nonempty literal member sets".into());
124 }
125 let topic_names: BTreeSet<_> = topic_members.iter().map(|(name, _)| *name).collect();
126 let guest_names: BTreeSet<_> = guest_members.iter().map(|(name, _)| *name).collect();
127 if !topic_names.is_disjoint(&guest_names)
128 || topic_names
129 .iter()
130 .chain(guest_names.iter())
131 .any(|name| ASSIGNMENTS.contains(name) || ["Man", "Woman", "NA", "T"].contains(name))
132 {
133 return Err("enum members collide with the wedding model's identifiers".into());
134 }
135 validate_records(&records, &guest_names, topic_members.len())?;
136 let same_members = group_members(&same, &guest_names)?;
137 let different_members = group_members(&different, &guest_names)?;
138 let table_item = items
139 .items()
140 .iter()
141 .find(|item| item.name == Some("Tables"))
142 .unwrap();
143 let (table_count, table_range) = table_constructor(&input, &table_item.range)?;
144 let capacity_values = positional(&capacities)?;
145 if capacity_values.len() != table_count
146 || capacity_values
147 .iter()
148 .any(|value| !matches!(value.kind, LiteralKind::Integer))
149 || !matches!(imbalance.kind, LiteralKind::Integer)
150 {
151 return Err("table_capacities must contain one literal integer per table; imbalance must be a literal integer".into());
152 }
153 let grown_tables = table_count
154 .checked_mul(factor)
155 .filter(|count| i64::try_from(*count).is_ok())
156 .ok_or("table count overflow")?;
157 if factor == 1 {
158 return Ok(input.source_bytes().to_vec());
159 }
160 let mut occupied: BTreeSet<String> = input
161 .syntax()
162 .tokens()
163 .iter()
164 .enumerate()
165 .filter(|(_, token)| {
166 matches!(
167 token.kind,
168 TokenKind::Identifier | TokenKind::QuotedIdentifier
169 )
170 })
171 .map(|(index, _)| {
172 String::from_utf8_lossy(input.token_bytes(index))
173 .trim_matches('\'')
174 .to_owned()
175 })
176 .collect();
177 let mut mappings = Vec::new();
178 for copy in 1..factor {
179 let mut mapping = BTreeMap::new();
180 for (index, (name, _)) in guest_members.iter().enumerate() {
181 let generated = format!("GrownGuest_{copy}_{}", index + 1);
182 if !occupied.insert(generated.clone()) {
183 return Err(format!("generated guest identifier collides: {generated}"));
184 }
185 mapping.insert(*name, generated);
186 }
187 mappings.push(mapping);
188 }
189 let LiteralKind::Array { entries, .. } = &records.kind else {
190 unreachable!()
191 };
192 let record_keys: Vec<_> = entries
193 .iter()
194 .map(|entry| {
195 let key = entry.key.as_ref().unwrap();
196 let LiteralKind::Member(name) = key.kind else {
197 unreachable!()
198 };
199 (name, key.range.clone())
200 })
201 .collect();
202 let mut edits = Vec::new();
203 for (value, replacements) in [
204 (&guests, guest_members),
205 (&records, record_keys),
206 (&same, same_members),
207 (&different, different_members),
208 (&capacities, Vec::new()),
209 ] {
210 edits.push(copy_collection(&input, value, &replacements, &mappings)?);
211 }
212 edits.push(TextEdit {
213 range: table_range,
214 replacement: vec![EditPart::Text(grown_tables.to_string())],
215 });
216 // Charge the exact final byte count before the public edit API allocates it.
217 let mut output_len = input.source_bytes().len();
218 for edit in &edits {
219 output_len -= edit.range.len();
220 for part in &edit.replacement {
221 let len = match part {
222 EditPart::Text(text) => text.len(),
223 EditPart::Original(range) => range.len(),
224 };
225 output_len = output_len
226 .checked_add(len)
227 .filter(|n| *n <= MAX_OUTPUT)
228 .ok_or("candidate exceeds 16 MiB")?;
229 }
230 }
231 let snapshot = SourceSnapshot::new("wedding.dzn", input.source_bytes());
232 let candidate = prepare_text_edits(&snapshot, input.source_bytes(), &edits)
233 .map_err(|error| error.to_string())?;
234 Input::parse_named(candidate.clone(), FileMode::Data, "grown-wedding.dzn")
235 .map_err(|error| format!("invalid candidate: {error:?}"))?;
236 Ok(candidate)
237}Sourcepub fn is_document(&self) -> bool
pub fn is_document(&self) -> bool
Only the untouched initial selection or items emits the whole document.
Trait Implementations§
Auto Trait Implementations§
impl<'a> Freeze for Selection<'a>
impl<'a> RefUnwindSafe for Selection<'a>
impl<'a> Send for Selection<'a>
impl<'a> Sync for Selection<'a>
impl<'a> Unpin for Selection<'a>
impl<'a> UnsafeUnpin for Selection<'a>
impl<'a> UnwindSafe for Selection<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more