Skip to main content

Input

Struct Input 

Source
pub struct Input { /* private fields */ }
Available on crate features input-toml or input-yaml only.
Expand description

A named text, ready to parse and validate.

The name is usually the file’s path, and appears in every problem. Build one with Input::new_with_format for text in memory, or Input::open for a file. With input-yaml, Input::new and Input::read build a YAML one.

Implementations§

Source§

impl Input

Source

pub fn top_level(&self) -> Result<Vec<Entry>, InputError>

The entries of the text’s top-level mapping or table, in the order written.

An entry whose key is not a string, such as a YAML key that is a number, a sequence or an alias, is left out, and the entries around it keep their own ranges. A text whose root is no mapping, such as a sequence or a scalar, has no entries. The text must pass the limits in force, as Input::parse holds it to, and a YAML input builds the document that Input::place keeps.

use ctl_core::input::Input;

let input = Input::new("page.yaml", "title: A page\nyear: 2026\n");
let entries = input.top_level()?;
let title = &entries[0];
assert_eq!(title.key, "title");
assert_eq!(&input.text()[title.value.clone()], "A page");
assert_eq!(title.string.as_deref(), Some("A page"));
assert_eq!(entries[1].string, None);
§Errors

An InputError with the parser’s problem and its line, as Input::parse gives, including a duplicate key, a YAML merge key and a text past a limit.

Source§

impl Input

Source

pub fn new(name: impl Into<String>, text: impl Into<String>) -> Self

Available on crate feature input-yaml only.

A YAML input from text already in memory, whatever the extension of name. Set another format with Input::format.

Source

pub fn new_with_format( name: impl Into<String>, text: impl Into<String>, format: Format, ) -> Self

An input of format from text already in memory, whatever the extension of name. It needs only format’s feature, so a build without YAML builds text in memory with it.

Source

pub fn read(path: &Path) -> Result<Self, InputError>

Available on crate feature input-yaml only.

Read a YAML file, named by its path, whatever its extension.

§Errors

An InputError with the I/O failure.

Source

pub fn open(path: &Path) -> Result<Self, InputError>

Read a file and take its Format from its extension, as Format::of does. The extension is checked before the file is read.

§Errors

An InputError for an extension Format::of refuses, or with the I/O failure.

Source

pub fn format(self, format: Format) -> Self

Set how the text is written, over what the constructor took.

Source

pub fn name(&self) -> &str

The name given at construction, usually the file’s path.

Source

pub fn text(&self) -> &str

The text as read, unchanged.

Source

pub fn frontmatter(&self) -> Option<(Self, &str)>

Available on crate feature input-yaml only.

Split YAML frontmatter from a Markdown body.

The frontmatter is the text between a first line of --- and the next line of ---. It is YAML whatever this input’s format, and problems in it keep the line numbers of the whole file. The second item is the body after the closing line. Returns None when the text does not start with a --- line, or never closes it.

Source

pub fn limits(self, limits: Limits) -> Self

Override limits for this input alone, above every other tier. See Limits for the order.

Source

pub fn flattened(self, field: FieldPath) -> Self

Available on crate feature validate only.

Declare that the schema field at field is flattened into its parent with #[serde(flatten)], so the file writes its entries directly under the parent.

garde names the field in each problem’s path all the same, and serde gives no sign of the flattening at run time, so the schema declares it. Input::check then drops the field’s step from each garde path whose leading steps are field, before it places the problem and prints its field. field is written in the schema’s terms, the way garde names it, and each call adds one field. A declaration that matches no garde path changes nothing. Input::place, Input::place_key, and Input::problem_at take paths in the file’s terms, so a declaration does not touch them.

§Examples

verctl’s assets holds its targets in a flattened map field targets. Without the declaration, the problem prints as assets.targets.linux-x64.files and sits on the line below assets:.

use std::collections::BTreeMap;

use ctl_core::input::{FieldPath, Input};
use ctl_core::validate::at_least_one;
use garde::Validate;
use serde::Deserialize;

#[derive(Debug, Deserialize, Validate)]
struct Config {
    #[garde(dive)]
    assets: Assets,
}

#[derive(Debug, Deserialize, Validate)]
struct Assets {
    #[serde(flatten)]
    #[garde(dive)]
    targets: BTreeMap<String, Target>,
}

#[derive(Debug, Deserialize, Validate)]
struct Target {
    #[garde(custom(at_least_one("file")))]
    files: Vec<String>,
}

let error = Input::new("ver.yaml", "assets:\n  linux-x64:\n    files: []\n")
    .flattened(FieldPath::root().key("assets").key("targets"))
    .load::<Config>()
    .unwrap_err();
assert_eq!(
    error.to_string(),
    "ver.yaml:3:12: assets.linux-x64.files: must declare at least one file"
);
Source

pub fn parse<T: DeserializeOwned>(&self) -> Result<T, InputError>

Parse the text into T, without validating it.

In YAML only true and false are booleans, and a duplicate key or a merge key (<<) is refused. In TOML the format itself refuses a duplicate key.

The text must fit the limits in force, decided field by field through the tiers Limits lists. TOML reads only max_reader_input_bytes, max_depth, and max_nodes, because the other fields name YAML syntax.

§Errors

An InputError with the parser’s problem and its line. A limit problem names the limit, its value, and where to raise it, or, without input-yaml, that the tool sets it.

Source

pub fn check<T: Validate + ?Sized>( &self, value: &T, context: &T::Context, ) -> Result<(), InputError>

Available on crate feature validate only.

Validate a parsed value against context.

Each of garde’s problems lands on the line of the field it names, or of its nearest written ancestor. The place comes from the parts of garde’s path through Input::place, so a key that holds a . is found as one key. Problem::field is garde’s printed path, for display only. A path through a field Input::flattened declares loses that field’s step, and its Problem::field is the shorter path as FieldPath prints it.

§Errors

An InputError with every problem garde reports.

Source

pub fn place(&self, path: &FieldPath) -> Option<Place>

Where path is written in the text, or where its nearest written ancestor is.

The line counts the whole file, so a frontmatter input adds the lines before it. A path the text lacks gives the place of the last step that exists, and a caller that needs an exact hit compares the result with the place of the path’s parent. None when the text does not parse.

None too when the text goes past the limits in force, as Input::parse would refuse it, so placing never parses a text the limits keep out. A YAML input checks max_reader_input_bytes, max_depth and max_nodes before it hands the text to yamled, which has no budget. A TOML input checks max_reader_input_bytes, and the parse of its tree is the one Input::parse does first.

A YAML input parses its text for the first placing and keeps the result, so Input::check and later calls read one document. A TOML input parses its text on each call.

use ctl_core::input::{FieldPath, Input};

let input = Input::new("app.yaml", "files:\n  'docs/**/*.md':\n    label: ''\n");
let path = FieldPath::root()
    .key("files")
    .key("docs/**/*.md")
    .key("label");
let at = input.place(&path).map(|at| (at.line, at.column));
assert_eq!(at, Some((3, 12)));
Source

pub fn place_key(&self, path: &FieldPath) -> Option<Place>

Where the last step of path is written as a key, or where its nearest written ancestor’s key is.

Input::place gives where a value starts. For a scalar or a flow value that is the line of the key, and for a block mapping or a block list it is the first line below it. A fault about the key itself, such as a key that names nothing, belongs on the key, and this finds it.

A step that is an index has no key, and neither has the root, so they give the place of their value, as place does. A path the text lacks gives the key of the last step that exists. The line counts the whole file, None is for a text that does not parse or goes past the limits, and a YAML document is built once and shared with Input::place.

use ctl_core::input::{FieldPath, Input};

let input = Input::new("app.yaml", "files:\n  'docs/**/*.md':\n    label: ''\n");
let glob = FieldPath::root().key("files").key("docs/**/*.md");
let value = input.place(&glob).map(|at| (at.line, at.column));
let key = input.place_key(&glob).map(|at| (at.line, at.column));
assert_eq!(value, Some((3, 5)));
assert_eq!(key, Some((2, 3)));
Source

pub fn problem_at( &self, path: &FieldPath, message: impl Into<String>, ) -> Problem

A Problem for path with message, placed as Input::place places it, with the path printed as garde prints a field.

A CLI uses it for a check that runs after the read, such as one that needs a file the config names.

Source

pub fn load<T>(&self) -> Result<T, InputError>

Available on crate feature validate only.

Parse the text into T, then validate it with T’s default context.

§Errors

As Input::parse and Input::check.

Trait Implementations§

Source§

impl Clone for Input

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Input

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Eq for Input

Source§

impl PartialEq for Input

Source§

fn eq(&self, other: &Self) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for Input

Auto Trait Implementations§

§

impl !Freeze for Input

§

impl Forget for Input

§

impl Move for Input

§

impl RefUnwindSafe for Input

§

impl Send for Input

§

impl Sync for Input

§

impl Unpin for Input

§

impl UnsafeUnpin for Input

§

impl UnwindSafe for Input

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

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, O> Matches<O> for T
where T: PartialEq<O>,

Source§

fn validate_matches(&self, other: &O) -> bool

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.