Skip to main content

Selection

Struct Selection 

Source
pub struct Selection<'a> { /* private fields */ }

Implementations§

Source§

impl<'a> Selection<'a>

Source

pub fn input(&self) -> &'a Input

Source

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}
Source

pub fn is_document(&self) -> bool

Only the untouched initial selection or items emits the whole document.

Trait Implementations§

Source§

impl<'a> Debug for Selection<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.