Added mini-tutorial.

[?]
CrEcTsRjb1hHQjHuumqRfqdbVV4X58iLEubi4noaDPFa
Jul 26, 2021, 1:43 AM
GMZ22FTMR2IJWPF7DXHIXRIQPWBOS4CT7BIABTKYBM4CUXKCNWZAC

Dependencies

  • [2] KD6IJRPT Improved header documentation.
  • [3] INHPVRSE Made some functions pub (crate). Added opt_vec_value() fn. Improved docs.
  • [4] 6ZJX2OQV First commit
  • [5] BRO5BHI2 Added val() function to KeyTreeRef.
  • [6] VDFODD2F Added line to BadIndent error.
  • [7] QMBJ2BAZ Can now handle FromStr.

Change contents

  • replacement in src/lib.rs at line 4
    [2.3020][2.3020:3153]()
    //! data-structures. It is easy to implement for one's own types. Its main use is
    //! for configuration files. The format looks like
    [2.3020]
    [2.3153]
    //! data-structures.
    //!
    //! # Mini-Tutorial
  • edit in src/lib.rs at line 8
    [2.3158]
    [2.3158]
    //! Lets say we have a struct like
    //! ```
    //! struct Hobbit {
    //! name: String,
    //! age: u32,
    //! friends: Vec<Hobbit>,
    //! nick: Option<String>,
    //! }
    //! ```
    //! and we want to record in a file how to create an instance of this struct. So we create a string
    //! like
  • edit in src/lib.rs at line 32
    [2.3458]
    [2.3458]
    //! Now we need to tell the struct how to select the the relevant part of this string, so for
    //! instance we need to tell the struct that we get the name by following the path
    //! `hobbit::name`. This selection mechanism has to be somewhat more sophisticated because we want
    //! to be able to select a `Vec` by, for instance, using the `hobbit::friends::hobbit` path to
    //! select both of Frodo's friends. Once we have selected the set of lines in the string we need a
    //! way to tell the data-structure how to convert that line into the correct type for the
    //! data-structure. To do this we need to implement the `FromStr` trait (if the field type does not
    //! already implement one) for the, so that the data-structure can take the selected key-values, and
    //! convert them to the field type. If the field type is a type `T` that we have built, we can
    //! implement `TryInto<T>` on it. The ! `TryInto` implementation for `Hobbit` looks like
    //! ```
    //! impl<'a> TryInto<Hobbit> for KeyTreeRef<'a> {
    //! type Error = Error;
  • replacement in src/lib.rs at line 46
    [2.3463][2.3463:3626]()
    //! so data can be recursive. Also, it is easy to refer to a set of data using a path such as
    //! `hobbit::friends::hobbit` refers to a collection of two hobbits.
    [2.3463]
    [2.3626]
    //! fn try_into(self) -> Result<Hobbit, Error> {
    //! Ok(
    //! Hobbit {
    //! name: self.value("hobbit::name")?,
    //! age: self.value("hobbit::age")?,
    //! friends: self.opt_vec_at("hobbit::friends::hobbit")?,
    //! nick: self.opt_value("hobbit::nick")?,
    //! }
    //! )
    //! }
    //! }
    //! ```
    //! The important functions are
    //! ```
    //! name: self.value("hobbit::name")?
    //! ```
    //! and which converts from a string and
    //! ```
    //! hobbit: self.at("hobbit")?
    //! ```
    //! which converts to a type `T` implementing the `TryInto<T>` trait. Then there are variations of
    //! `value()` and `at()` for handling conversions into `Options`:
    //!
    //! ```
    //! self.opt_value()
    //! ```
    //! and
    //! ```
    //! self.opt_at()
    //! ```
    //! In these cases, if the selected key-value does not exist, we get a `None` value. To convert into
    //! a `Vec` we can use
    //! ```
    //! self.vec_value()
    //! ```
    //! and
    //! ```
    //! self.vec_at()
    //! ```
    //! which require at least one key-value and
    //! ```
    //! self.opt_vec_at()
    //! ```
    //! and
    //! ```
    //! self.opt_vec_value()
    //! ```
    //! which will return an empty `Vec` if the key-value does not exist.
  • edit in src/lib.rs at line 151
    [2.5315][2.5315:5972]()
    //! ```
    //!
    //! In the `TryInto` implementation that deserializes the keytree string into a data-structure, the
    //! line
    //! ```
    //! name: self.value("hobbit::name")?,
    //! ```
    //! takes the value on the line specified by `hobbit:name` (`Frodo Baggins`) and then uses the
    //! `FromStr` implement to convert it into the receiver type of the `name` field which is type
    //! `String`.
    //!
    //! The line
    //! ```
    //! friends: self.vec_at("hobbit::friends::hobbit")?,
    //! ```
    //! takes the collection of lines
    //! ```text
    //! hobbit:
    //! name: Bilbo Baggins
    //! age: 111
    //! hobbit:
    //! name: Samwise Gamgee
    //! age: 38
    //! nick: Sam
  • edit in src/lib.rs at line 152
    [2.5980][2.5980:6116]()
    //! and then uses the `TryInto` implementation of the items in the receiving type `Hobbit` to map
    //! itself into a `Vec` of `Hobbit`s.
  • replacement in src/lib.rs at line 153
    [2.6120][2.6120:6145]()
    //! ## Data Format Rules
    [2.6120]
    [2.6145]
    //! ## Data Specification
  • replacement in src/lib.rs at line 191
    [2.7308][2.7308:7374]()
    //! - Comments require `//` at the start of the line. For example
    [2.7308]
    [2.7374]
    //! - A comment line starts witha any amount of whitespace followed by `//`.
  • edit in src/lib.rs at line 196
    [2.7418]
    [2.7418]
    //! // another comment
  • edit in src/lib.rs at line 199
    [2.7446]
    [4.18442]
    //! ## Efficiency
    //!
    //! There are no copies of the original string. The parsing process builds of immutable tree-structure which
    //! points into the original string. Selection operations involve the manipulation of a single `usize`
    //! cursor, so once A `KeyTree` is built, many lightweight `KeyTree` refs can be efficiently built
    //! and used for searching. So the only string copy that occurs is the final conversion into the
    //! receiving data-structure. Following a path into a keytree involves a scan of differently names
    //! siblings held in a Vec. The assumption is that the number of different sibling names is
    //! generally small because the number of fields in data-structures is also generally small. From
    //! the point of view of compile time, there are no dependencies and no macros.
  • edit in src/lib.rs at line 505
    [4.1257][3.357:420]()
    /// Returns a `T: FromStr` where `T` is the receiver type.
  • edit in src/lib.rs at line 507
    [3.467]
    [3.467]
    /// use std::str::FromStr;
    ///
  • replacement in src/lib.rs at line 511
    [3.539][3.539:632]()
    ///
    /// static TEMP: &'static str = r#"example:
    /// temp: -15.3"#;
    ///
    [3.539]
    [3.632]
    ///
    /// static TEMP: &'static str = r#"
    /// example:
    /// temp: -15.3
    /// "#;
    ///
    /// #[derive(Debug)]
  • replacement in src/lib.rs at line 519
    [3.665][3.665:673]()
    ///
    [3.665]
    [3.673]
    ///
  • replacement in src/lib.rs at line 521
    [3.712][3.712:769]()
    /// let Err = std::num::ParseFloatError;
    ///
    [3.712]
    [3.769]
    /// type Err = std::num::ParseFloatError;
    ///
  • replacement in src/lib.rs at line 524
    [3.831][3.831:861]()
    /// self.parse(s)
    [3.831]
    [3.861]
    /// s.parse()
  • replacement in src/lib.rs at line 527
    [3.885][3.885:894]()
    ///
    [3.885]
    [3.894]
    ///
  • replacement in src/lib.rs at line 530
    [3.985][3.985:1051]()
    ///
    /// fn try_into(self) -> Result<Hobbit, Error> {
    [3.985]
    [3.1051]
    ///
    /// fn try_into(self) -> Result<Temperature, Error> {
  • replacement in src/lib.rs at line 535
    [3.1137][3.1137:1146]()
    ///
    [3.1137]
    [3.1146]
    ///
  • edit in src/lib.rs at line 539
    [3.1287]
    [3.1287]
    /// println!("{:?}", temp);
    /// // Temperature(-15.3)