Skip to main content

tablo_core/values/
parse.rs

1//! The reads of one key from a completed submission: a scalar, a password, a multiple choice's
2//! list, and the write of that list.
3
4use super::{FieldError, FormScalar, FormValue, FormValues, unreadable};
5
6/// Read one scalar from a completed submission.
7///
8/// Trims the value; an empty one is `blank`, the field's blank answer, or
9/// refuses as [`FieldErrorKind::Required`](super::FieldErrorKind::Required) when it has none.
10pub fn parse_scalar<T: FormScalar>(
11    key: &str,
12    values: &FormValues,
13    blank: Option<T>,
14) -> std::result::Result<T, FieldError> {
15    let raw = match values.get(key) {
16        None => "",
17        Some(FormValue::Text(text)) => text.trim(),
18        Some(_) => return Err(unreadable(key)),
19    };
20    if raw.is_empty() {
21        return blank.ok_or_else(|| FieldError::required(key));
22    }
23    T::parse_form(raw).map_err(|message| FieldError::invalid(key, message))
24}
25
26/// Read a password from a completed submission: required as [`parse_scalar`] reads a `String`,
27/// but kept as typed, with its outer spaces, since a login compares the password untrimmed.
28pub fn parse_password(
29    key: &str,
30    values: &FormValues,
31    blank: Option<String>,
32) -> std::result::Result<String, FieldError> {
33    parse_scalar::<String>(key, values, blank)?;
34    Ok(values.text(key).unwrap_or_default().to_string())
35}
36
37/// The values a multiple choice holds, as its one form key carries them: what a record form
38/// hydrates a many-to-many field with, and what a hand-written one writes.
39pub fn write_list<'a, T: FormScalar + 'a>(values: impl IntoIterator<Item = &'a T>) -> FormValue {
40    FormValue::List(values.into_iter().map(T::to_form).collect())
41}
42
43/// Read the values a multiple choice posted, none when it posted nothing: what a record form's
44/// parse reads a many-to-many field with.
45///
46/// # Errors
47///
48/// A value `T` refuses, or a key holding no list, under `key`.
49pub fn parse_list<T: FormScalar>(
50    key: &str,
51    values: &FormValues,
52) -> std::result::Result<Vec<T>, FieldError> {
53    let items: &[String] = match values.get(key) {
54        None => &[],
55        Some(FormValue::List(items)) => items,
56        Some(_) => return Err(unreadable(key)),
57    };
58    items
59        .iter()
60        .map(|item| T::parse_form(item).map_err(|message| FieldError::invalid(key, message)))
61        .collect()
62}
63
64#[cfg(test)]
65mod tests;