~ioiojo/kiwi

a5230f69102aceb376d2218aab6a086889923d60 — Andy Weidenbaum 2 years ago f18b483
s/’/' to be more tty friendly
M src/cli_command.rs => src/cli_command.rs +1 -1
@@ 90,7 90,7 @@ pub fn load_diet(base: BaseOpts, opts: ShowDietOpts) -> CliResult<Diet> {
            .collect();

        // Post-filtering, `dine` may not contain at least one `Dine`. Return an error if
        // it doesn’t.
        // it doesn't.
        if dine.len() > 0 {
            Ok(Diet { dine })
        } else {

M src/cli_error.rs => src/cli_error.rs +6 -6
@@ 123,13 123,13 @@ pub enum CliError {
    /// Could not find Kiwi Lua library source from `include_fnl!`.
    MissingKiwiLuaLibrarySource,

    /// Could not find directory separator (e.g. `/`) in Lua’s `package.config`.
    /// Could not find directory separator (e.g. `/`) in Lua's `package.config`.
    MissingPackageConfigDirSep,

    /// Could not find path separator (e.g. `;`) in Lua’s `package.config`.
    /// Could not find path separator (e.g. `;`) in Lua's `package.config`.
    MissingPackageConfigPathSep,

    /// Could not find path mark (e.g. `?`) in Lua’s `package.config`.
    /// Could not find path mark (e.g. `?`) in Lua's `package.config`.
    MissingPackageConfigPathMark,

    /// Missing `--config` option value.


@@ 378,13 378,13 @@ impl std::fmt::Display for CliError {
                "Could not find Kiwi Lua library source from `include_fnl!`".to_string()
            }
            CliError::MissingPackageConfigDirSep => {
                "Could not find directory separator (e.g. `/`) in Lua’s `package.config`".to_string()
                "Could not find directory separator (e.g. `/`) in Lua's `package.config`".to_string()
            }
            CliError::MissingPackageConfigPathSep => {
                "Could not find path separator (e.g. `;`) in Lua’s `package.config`".to_string()
                "Could not find path separator (e.g. `;`) in Lua's `package.config`".to_string()
            }
            CliError::MissingPackageConfigPathMark => {
                "Could not find path mark (e.g. `?`) in Lua’s `package.config`".to_string()
                "Could not find path mark (e.g. `?`) in Lua's `package.config`".to_string()
            }
            CliError::MissingKiwiConfigPathValue => "Missing `--config` option value".to_string(),
            CliError::MissingKiwiDirValue => "Missing `--kiwi-dir` option value".to_string(),

M src/cli_opts.rs => src/cli_opts.rs +2 -2
@@ 8,10 8,10 @@ use crate::cli_error::CliError;
use crate::cli_types::{CliResult, Mode};
use crate::plan_types::{ActivityLevel, Gender};

/// Default basename of Kiwi’s global configuration file.
/// Default basename of Kiwi's global configuration file.
const BASENAME: &str = "kiwi.conf";

/// Default directory name for Kiwi’s global configuration file.
/// Default directory name for Kiwi's global configuration file.
const DIRNAME: &str = "kiwi";

/// The complete set of options passed on the cmdline.

M src/cli_setup.rs => src/cli_setup.rs +4 -4
@@ 92,7 92,7 @@ impl<'a> Setup<'a> for Context<'a> {
        let kiwi_dir = base.kiwi_dir()?;
        self.setup_kiwi_searcher_paths(kiwi_config_home.as_path(), kiwi_dir.as_path())?;

        // Enable Lua’s module loader to load Fennel modules residing on `fennel.path` by
        // Enable Lua's module loader to load Fennel modules residing on `fennel.path` by
        // adding `fennel.searcher` to `package.searchers`.
        self.load(r#"table.insert(package.searchers, require("fennel").searcher)"#)
            .eval()


@@ 116,7 116,7 @@ impl<'a> Setup<'a> for Context<'a> {
                path: kiwi_dir.to_owned(),
            })?;

        // Obtain handles to Lua’s global `package` and `fennel` tables.
        // Obtain handles to Lua's global `package` and `fennel` tables.
        let globals: Table = self.globals();
        let package: Table = globals.get("package")?;
        let fennel: Table = self.load(r#"return require("fennel")"#).eval()?;


@@ 254,7 254,7 @@ impl<'a> LoadProfile for Context<'a> {
        // Wrap `require` in `pcall` to handle optionality of `profile` module.
        let ok_module: MultiValue = self.load(r#"return pcall(require, "profile")"#).eval()?;

        // Lua’s `pcall` function returns a `MultiVal`, i.e. `(bool, Value)`.
        // Lua's `pcall` function returns a `MultiVal`, i.e. `(bool, Value)`.
        //
        // If the `pcall` was successful:
        //


@@ 289,7 289,7 @@ impl<'a> LoadProfile for Context<'a> {
            return Err(CliError::MissingProfileModule { cause });
        };

        // This could easily be an `.unwrap()`, because it’s assumed `load_kiwi_profile()`
        // This could easily be an `.unwrap()`, because it's assumed `load_kiwi_profile()`
        // is only called when `opts.name.is_some()`.
        let name: String = match opts.name.take() {
            Some(name) => name,

M src/dir.rs => src/dir.rs +4 -4
@@ 83,7 83,7 @@ impl TryFrom<DirArgs> for Dine {
        // Improves Lua API ergonomics and error reporting.
        //
        // Stores internal `DirErrorKind` type rather than `rlua::Error` due to the
        // latter’s limited expressivity (string only).
        // latter's limited expressivity (string only).
        let mut errors: Option<Vec<DirErrorKind>> = None;

        let (good_ip_date, good_ip_dicts, bad_dicts, good_ip_foods): (


@@ 534,7 534,7 @@ fn new_dine(
    mut good_ip_dicts: Option<Vec<(usize, Dict)>>,
    mut bad_dicts: Option<Vec<(usize, Dict)>>,
    good_ip_foods: Option<Vec<(usize, Food)>>,
    // We’ve already collected all errors detectable at a glance, e.g. erroneous and
    // We've already collected all errors detectable at a glance, e.g. erroneous and
    // unsupported input types. What errors remain will be missing data in most cases, or
    // food arithmetic errors in rare cases.
    mut errors: Option<Vec<DirErrorKind>>,


@@ 543,7 543,7 @@ fn new_dine(

    let mut dicts = match (good_ip_dicts.take(), bad_dicts.take()) {
        (Some(mut good_ip_dicts), Some(mut bad_dicts)) => {
            // Merge good and bad dicts. We’ve already collected the errors, and just
            // Merge good and bad dicts. We've already collected the errors, and just
            // want to see if we can salvage some valid data from the bad ones.
            good_ip_dicts.append(&mut bad_dicts);



@@ 567,7 567,7 @@ fn new_dine(
                            foods.push_or_init(food);
                        }
                        Err(e) => {
                            // Couldn’t convert `Quantity::ServingSize` to `ServingSize`.
                            // Couldn't convert `Quantity::ServingSize` to `ServingSize`.
                            let error = DictErrorKind::from(e);
                            errors.push_or_init(DirErrorKind::Dict { count, error });
                        }

M src/dir_arg.rs => src/dir_arg.rs +2 -2
@@ 38,7 38,7 @@ pub enum DirArg {

    /// An unsupported value.
    ///
    /// The inner value is the unsupported value’s Lua type.
    /// The inner value is the unsupported value's Lua type.
    Unsupported(&'static str),
}



@@ 98,7 98,7 @@ impl TryFrom<Table<'_>> for Dict {
            builder.constituents(constituents);
        }

        // All `Dict` fields are optional, and we’ve collected any erroneous keypairs
        // All `Dict` fields are optional, and we've collected any erroneous keypairs
        // encountered in `unsupported`.
        let dict = builder.build().expect("DictBuilder unexpectedly failed");


M src/dir_error.rs => src/dir_error.rs +5 -5
@@ 70,7 70,7 @@ impl DirError {
                .collect(),
        };

        // Anticipate rlua’s automatic insertion of “runtime error:”.
        // Anticipate rlua's automatic insertion of “runtime error:”.
        errors.insert(0, "Dine could not be instantiated".to_string());

        let errors = errors.join("\n\n");


@@ 218,7 218,7 @@ impl std::error::Error for InputFoodErrorKind {}

#[derive(Debug)]
pub enum DateStringErrorKind {
    /// `Dine` instantiation input datestring contents couldn’t be converted to UTF-8.
    /// `Dine` instantiation input datestring contents couldn't be converted to UTF-8.
    Malformed(InputDateStringError),

    /// `Dine` instantiation function got valid datestring input in an unexpected position.


@@ 233,7 233,7 @@ impl std::fmt::Display for DateStringErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let res = match self {
            DateStringErrorKind::Malformed(error) => format!(
                "`Dine` instantiation input datestring contents couldn’t be converted to UTF-8: {}",
                "`Dine` instantiation input datestring contents couldn't be converted to UTF-8: {}",
                error
            ),
            DateStringErrorKind::Unexpected(naive_date_time) => format!(


@@ 262,10 262,10 @@ pub enum DictErrorKind {
    /// `Dine` instantiation function got malformed table input in an unexpected position.
    UnexpectedMalformed(Vec<DictKeyPairError>),

    /// `Dine` instantiation function got valid table input with `Food` which couldn’t be
    /// `Dine` instantiation function got valid table input with `Food` which couldn't be
    /// multiplied.
    ///
    /// Couldn’t convert `Quantity::ServingSize` to `ServingSize`.
    /// Couldn't convert `Quantity::ServingSize` to `ServingSize`.
    FoodMath(FoodError),
}


M src/fir.rs => src/fir.rs +7 -7
@@ 28,11 28,11 @@ use crate::food_meta::{Aka, Meta, MetaBuilder};
const DOCSTRING_POSITION: usize = 0;

/// Error message designed for unwrapping `Result` from `Food::div()`, which should
/// always succeed given we’re passing in a number greater than zero.
/// always succeed given we're passing in a number greater than zero.
const FOOD_DIV_EXPECT: &str = "Food division operation unexpectedly failed";

/// Error message designed for unwrapping `Result` from `Food::mul()`, which should
/// always succeed given we’re passing in a number greater than or equal to zero.
/// always succeed given we're passing in a number greater than or equal to zero.
const FOOD_MUL_EXPECT: &str = "Food multiplication operation unexpectedly failed";

/// Error messages designed for reading `Option`-wrapped values from a collection of


@@ 100,7 100,7 @@ impl TryFrom<FirArgs> for Food {
        // Improves Lua API ergonomics and error reporting.
        //
        // Stores internal `FirErrorKind` type rather than `rlua::Error` due to the
        // latter’s limited expressivity (string only).
        // latter's limited expressivity (string only).
        let mut errors: Option<Vec<FirErrorKind>> = None;

        let (good_ip_docstring, good_ip_dicts, bad_dicts, good_ip_lists): (


@@ 570,7 570,7 @@ fn new_food(
    mut good_ip_dicts: Option<Vec<(usize, Dict)>>,
    mut bad_dicts: Option<Vec<(usize, Dict)>>,
    mut good_ip_lists: Option<Vec<(usize, List)>>,
    // We’ve already collected all errors detectable at a glance, e.g. erroneous keys and
    // We've already collected all errors detectable at a glance, e.g. erroneous keys and
    // values, and unsupported input types. What errors remain will tend to be missing or
    // duplicate data in most cases, or food arithmetic errors in rare cases.
    mut errors: Option<Vec<FirErrorKind>>,


@@ 591,7 591,7 @@ fn new_food(

    let mut dicts = match (good_ip_dicts.take(), bad_dicts.take()) {
        (Some(mut good_ip_dicts), Some(mut bad_dicts)) => {
            // Merge good and bad dicts. We’ve already collected the errors, and just
            // Merge good and bad dicts. We've already collected the errors, and just
            // want to see if we can salvage some valid data from the bad ones.
            good_ip_dicts.append(&mut bad_dicts);



@@ 950,7 950,7 @@ fn handle_constituents(
                        constituents.push(food);
                    }
                    Err(e) => {
                        // Couldn’t convert `Quantity::ServingSize` to `ServingSize`.
                        // Couldn't convert `Quantity::ServingSize` to `ServingSize`.
                        let error = DictErrorKind::from(e);
                        errors.push_or_init(FirErrorKind::Dict { count, error });
                    }


@@ 961,7 961,7 @@ fn handle_constituents(
                            constituents.push(food);
                        }
                        Err(e) => {
                            // Couldn’t convert `Quantity::ServingSize` to `ServingSize`.
                            // Couldn't convert `Quantity::ServingSize` to `ServingSize`.
                            let error = DictErrorKind::from(e);
                            errors.push_or_init(FirErrorKind::Dict { count, error });
                        }

M src/fir_arg.rs => src/fir_arg.rs +11 -11
@@ 40,7 40,7 @@ use crate::food_meta::Aka;
use crate::utils;

/// Error message for `Peekable::next().expect()`, designed for situations where a prior
/// call to `Peekable::peek()` has revealed the iterator’s next item exists.
/// call to `Peekable::peek()` has revealed the iterator's next item exists.
const PEEKABLE_NEXT_EXPECT: &str = "Peek-checked `Iterator` unexpectedly returned `None`";

/// Error message for `rlua::Table::get(1).expect()` — which should always succeed.


@@ 50,7 50,7 @@ const TABLE_GET_1_EXPECT: &str = "`rlua::Table::get(1)` unexpectedly failed";
const TABLE_GET_2_EXPECT: &str = "`rlua::Table::get(2)` unexpectedly failed";

/// Error message for `try_into::<NumberGteZero>().expect()`, designed for situations
/// where we don’t expect the conversion to fail.
/// where we don't expect the conversion to fail.
const TRY_INTO_RATIO_EXPECT: &str = "Ratio-checked value unexpectedly failed to convert into ratio";

/// A collection of `Result`-wrapped arguments paired with a numeric “count”.


@@ 89,7 89,7 @@ pub enum FirArg {

    /// An unsupported value.
    ///
    /// The inner value is the unsupported value’s Lua type.
    /// The inner value is the unsupported value's Lua type.
    Unsupported(&'static str),
}



@@ 112,20 112,20 @@ impl From<Value<'_>> for FirArg {
                FirArg::Dict(dict)
            }

            // Got a `Value` variant other than `Value::Table`. Assuming it’s a
            // Got a `Value` variant other than `Value::Table`. Assuming it's a
            // `Value::String`, because no other input type is supported.
            value => match value.try_into_string() {
                Ok(content) => FirArg::String(Ok(content)),
                Err(e) => match e {
                    // We were passed an `rlua::String`, but its contents couldn’t be
                    // We were passed an `rlua::String`, but its contents couldn't be
                    // converted to UTF-8.
                    InputStringError::MalformedString { content } => {
                        let error = Err(InputStringError::MalformedString { content });
                        FirArg::String(error)
                    }

                    // If we got here, we weren’t passed an `rlua::String` or an
                    // `rlua::Table`. Hence, we must’ve been passed an unsupported
                    // If we got here, we weren't passed an `rlua::String` or an
                    // `rlua::Table`. Hence, we must've been passed an unsupported
                    // input type.
                    InputStringError::MissingString { got } => FirArg::Unsupported(got),
                },


@@ 206,7 206,7 @@ impl TryFrom<Table<'_>> for Dict {
            builder.constituents(constituents);
        }

        // All `Dict` fields are optional, and we’ve collected any erroneous keypairs
        // All `Dict` fields are optional, and we've collected any erroneous keypairs
        // encountered in `unsupported`.
        let dict = builder.build().expect("DictBuilder unexpectedly failed");



@@ 694,7 694,7 @@ where
    I: Iterator<Item = Value<'a>>,
{
    // Avoids calling `iter.next()` unless the next item is a ratio. Theoretically
    // improves error reporting, by allowing to “skip over” what should’ve been a
    // improves error reporting, by allowing to “skip over” what should've been a
    // `Quantity` paired with a `Food`, and proceed onto the next `Food`-`Quantity` pair.
    match iter.peek() {
        Some(value) if value.is_ratio() => {


@@ 1070,13 1070,13 @@ impl TryFrom<Value<'_>> for AminoAcids {
                            .expect("AminoAcidsBuilder unexpectedly failed");

                        // Wrapping `amino_acids` in an `Ok` seems rather pointless, but
                        // the point is we don’t want to handle (truly) unexpected
                        // the point is we don't want to handle (truly) unexpected
                        // `builder.build()` errors.
                        Ok(amino_acids)
                    }

                    // `AminoAcidsBuilder::try_from(table)` returned `Err`, hence `table`
                    // must’ve contained unsupported keys.
                    // must've contained unsupported keys.
                    Err(e) => Err(e),
                }
            }

M src/fir_consts.rs => src/fir_consts.rs +6 -6
@@ 11,22 11,22 @@ pub const CREATE_REGISTRY_VALUE_EXPECT: &str = "Creating registry value unexpect
pub const META_BUILDER_DEFAULT_BUILD_EXPECT: &str = "`MetaBuilder` unexpectedly failed";

/// Error message for `Iterator::nth(0).expect()`, designed for situations where a prior
/// call to `Iterator::len(iter)` has revealed `iter`’s length to be at least one.
/// call to `Iterator::len(iter)` has revealed `iter`'s length to be at least one.
pub const NTH_EXPECT: &str = "Length-checked `Iterator` unexpectedly returned `None`";

/// Error message for `Iterator::Item.expect()` in `rlua::TablePairs`’ — which `rlua`
/// Error message for `Iterator::Item.expect()` in `rlua::TablePairs`es — which `rlua`
/// wraps in `Result` to facilitate lazily converting Lua types to Rust. Presumably this
/// can only fail if the user requests a Rust type which doesn’t implement `FromLua`.
/// can only fail if the user requests a Rust type which doesn't implement `FromLua`.
pub const PAIRS_EXPECT: &str = "`rlua::TablePairs::pairs()` unexpectedly failed";

/// Error message designed for situations where we’re sifting through partitioned data.
/// Error message designed for situations where we're sifting through partitioned data.
pub const PARTITIONED_EXPECT: &str = "Partitioning unexpectedly failed";

/// Error message designed for unwrapping `Result` from `rlua::Context::registry_value()`,
/// which should always succeed.
pub const REGISTRY_VALUE_EXPECT: &str = "Fetching registry value unexpectedly failed";

/// Error message for `Iterator::Item.expect()` in `rlua::TableSequence`’ — which `rlua`
/// Error message for `Iterator::Item.expect()` in `rlua::TableSequence`s — which `rlua`
/// wraps in `Result` to facilitate lazily converting Lua types to Rust. Presumably this
/// can only fail if the user requests a Rust type which doesn’t implement `FromLua`.
/// can only fail if the user requests a Rust type which doesn't implement `FromLua`.
pub const SEQUENCE_VALUES_EXPECT: &str = "`rlua::TableSequence` unexpectedly failed";

M src/fir_error.rs => src/fir_error.rs +26 -26
@@ 85,7 85,7 @@ impl FirError {
            }
        };

        // Anticipate rlua’s automatic insertion of “runtime error:”.
        // Anticipate rlua's automatic insertion of “runtime error:”.
        errors.insert(0, "Food could not be instantiated".to_string());

        let errors = errors.join("\n\n");


@@ 386,7 386,7 @@ pub enum ServingSizeError {
    /// got `got`.
    MissingNumber { got: &'static str },

    /// Second element of serving size list (string) couldn’t be converted to UTF-8.
    /// Second element of serving size list (string) couldn't be converted to UTF-8.
    MalformedUnitOfMeasureString { unit_of_measure: Vec<u8> },

    /// Expected second element of serving size list to be a string, but got `got`.


@@ 418,7 418,7 @@ impl std::fmt::Display for ServingSizeError {
                got
            ),
            ServingSizeError::MalformedUnitOfMeasureString { unit_of_measure } => format!(
                "Second element of serving size list (string) couldn’t be converted to UTF-8: {:?}",
                "Second element of serving size list (string) couldn't be converted to UTF-8: {:?}",
                unit_of_measure
            ),
            ServingSizeError::MissingUnitOfMeasureString { got } => format!(


@@ 464,7 464,7 @@ pub enum InputQuantityError {
    /// than or equal to zero, but got `got`.
    MissingServingSizeNumber { got: &'static str },

    /// Second element of `ServingSizeish` `Quantity` list (string) couldn’t be converted
    /// Second element of `ServingSizeish` `Quantity` list (string) couldn't be converted
    /// to UTF-8.
    MalformedServingSizeUnitOfMeasureString { unit_of_measure: Vec<u8> },



@@ 510,7 510,7 @@ impl std::fmt::Display for InputQuantityError {
                got
            ),
            InputQuantityError::MalformedServingSizeUnitOfMeasureString { unit_of_measure } => format!(
                "Second element of `ServingSizeish` `Quantity` list (string) couldn’t be converted to UTF-8: {:?}",
                "Second element of `ServingSizeish` `Quantity` list (string) couldn't be converted to UTF-8: {:?}",
                unit_of_measure
            ),
            InputQuantityError::MissingServingSizeUnitOfMeasureString { got } => format!(


@@ 597,7 597,7 @@ pub enum InputFoodAvgError {
    /// Expected `FoodAvgElem` instantiation input to be a table or `Food`, but got `got`.
    MissingElemTableOrFood { got: &'static str },

    /// Couldn’t convert `Quantity::ServingSize` to `ServingSize`.
    /// Couldn't convert `Quantity::ServingSize` to `ServingSize`.
    FoodMath(FoodError),
}



@@ 656,7 656,7 @@ impl std::error::Error for InputFoodAvgError {}

#[derive(Debug)]
pub enum StringErrorKind {
    /// `Food` instantiation input string contents couldn’t be converted to UTF-8.
    /// `Food` instantiation input string contents couldn't be converted to UTF-8.
    Malformed(InputStringError),

    /// `Food` instantiation function got valid string input in an unexpected position.


@@ 670,7 670,7 @@ impl std::fmt::Display for StringErrorKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let res = match self {
            StringErrorKind::Malformed(error) => format!(
                "`Food` instantiation input string contents couldn’t be converted to UTF-8: {}",
                "`Food` instantiation input string contents couldn't be converted to UTF-8: {}",
                error
            ),
            StringErrorKind::Unexpected(string) => format!(


@@ 699,16 699,16 @@ pub enum DictErrorKind {
    /// `Food` instantiation function got malformed table input in an unexpected position.
    UnexpectedMalformed(Vec<DictKeyPairError>),

    /// `Food` instantiation function got valid table input with `Food` which couldn’t be
    /// `Food` instantiation function got valid table input with `Food` which couldn't be
    /// multiplied.
    ///
    /// Couldn’t convert `Quantity::ServingSize` to `ServingSize`.
    /// Couldn't convert `Quantity::ServingSize` to `ServingSize`.
    FoodMath(FoodError),

    /// `Food` instantiation function got valid table input with list of `Food`s at least
    /// one of which couldn’t be multiplied.
    /// one of which couldn't be multiplied.
    ///
    /// Couldn’t convert `Quantity::ServingSize` to `ServingSize`.
    /// Couldn't convert `Quantity::ServingSize` to `ServingSize`.
    FoodAvgMath(InputFoodAvgError),
}



@@ 778,7 778,7 @@ pub enum DictKeyPairError {
        got: &'static str,
    },

    /// `Food` instantiation input table string key couldn’t be converted to UTF-8.
    /// `Food` instantiation input table string key couldn't be converted to UTF-8.
    MalformedKeyString {
        key: Vec<u8>,
    },


@@ 823,7 823,7 @@ impl std::fmt::Display for DictKeyPairError {
                got
            ),
            DictKeyPairError::MalformedKeyString { key } => format!(
                "`Food` instantiation input table string key couldn’t be converted to UTF-8: {:?}",
                "`Food` instantiation input table string key couldn't be converted to UTF-8: {:?}",
                key
            ),
            DictKeyPairError::UnexpectedKeyString { key, value } => format!(


@@ 920,10 920,10 @@ impl std::error::Error for DictKeyPairError {}

#[derive(Debug)]
pub enum DictAkaError {
    /// `Food` instantiation input table `aka` string couldn’t be converted to UTF-8.
    /// `Food` instantiation input table `aka` string couldn't be converted to UTF-8.
    MalformedString { aka: Vec<u8> },

    /// `Food` instantiation input table `aka` list element string couldn’t be converted
    /// `Food` instantiation input table `aka` list element string couldn't be converted
    /// to UTF-8.
    MalformedListString { elem: Vec<u8> },



@@ 944,11 944,11 @@ impl std::fmt::Display for DictAkaError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let res = match self {
            DictAkaError::MalformedString { aka } => format!(
                "`Food` instantiation input table `aka` string couldn’t be converted to UTF-8: {:?}",
                "`Food` instantiation input table `aka` string couldn't be converted to UTF-8: {:?}",
                aka
            ),
            DictAkaError::MalformedListString { elem } => format!(
                "`Food` instantiation input table `aka` list element string couldn’t be converted to UTF-8: {:?}",
                "`Food` instantiation input table `aka` list element string couldn't be converted to UTF-8: {:?}",
                elem
            ),
            DictAkaError::MissingListString { got } => format!(


@@ 1045,7 1045,7 @@ pub enum DictAminoAcidsKeyPairError {
        got: &'static str,
    },

    /// `Food` instantiation input table `amino-acids` table string key couldn’t be
    /// `Food` instantiation input table `amino-acids` table string key couldn't be
    /// converted to UTF-8.
    MalformedKeyString {
        key: Vec<u8>,


@@ 1085,7 1085,7 @@ impl std::fmt::Display for DictAminoAcidsKeyPairError {
                got
            ),
            DictAminoAcidsKeyPairError::MalformedKeyString { key } => format!(
                "`Food` instantiation input table `amino-acids` table string key couldn’t be converted to UTF-8: {:?}",
                "`Food` instantiation input table `amino-acids` table string key couldn't be converted to UTF-8: {:?}",
                key
            ),
            DictAminoAcidsKeyPairError::UnexpectedKeyString { key, value } => format!(


@@ 2108,7 2108,7 @@ impl std::error::Error for DictAlcoholError {}

#[derive(Debug)]
pub enum DictSourceError {
    /// `Food` instantiation input table `source` string couldn’t be converted to UTF-8.
    /// `Food` instantiation input table `source` string couldn't be converted to UTF-8.
    MalformedString { source: Vec<u8> },

    /// Expected `Food` instantiation input table `source` value to be a string, but got


@@ 2120,7 2120,7 @@ impl std::fmt::Display for DictSourceError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let res = match self {
            DictSourceError::MalformedString { source } => format!(
                "`Food` instantiation input table `source` string couldn’t be converted to UTF-8: {:?}",
                "`Food` instantiation input table `source` string couldn't be converted to UTF-8: {:?}",
                source
            ),
            DictSourceError::MissingString { got } => format!(


@@ 2136,7 2136,7 @@ impl std::error::Error for DictSourceError {}

#[derive(Debug)]
pub enum DictPerError {
    /// `Food` instantiation input table `per` table keypair key string couldn’t be
    /// `Food` instantiation input table `per` table keypair key string couldn't be
    /// converted to UTF-8.
    MalformedTableKeyUnitOfMeasureString { unit_of_measure: Vec<u8> },



@@ 2157,7 2157,7 @@ pub enum DictPerError {
    MissingTableValueServingSizeNumber { got: &'static str },

    /// Second element of `Food` instantiation input table `per` table keypair value list
    /// couldn’t be converted to UTF-8.
    /// couldn't be converted to UTF-8.
    MalformedTableValueServingSizeUnitOfMeasureString { unit_of_measure: Vec<u8> },

    /// Expected second element of `Food` instantiation input table `per` table keypair


@@ 2192,7 2192,7 @@ impl std::fmt::Display for DictPerError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let res = match self {
            DictPerError::MalformedTableKeyUnitOfMeasureString { unit_of_measure } => format!(
                "`Food` instantiation input table `per` table keypair key string couldn’t be converted to UTF-8: {:?}",
                "`Food` instantiation input table `per` table keypair key string couldn't be converted to UTF-8: {:?}",
                unit_of_measure
            ),
            DictPerError::MissingTableKeyUnitOfMeasureString { got } => format!(


@@ 2212,7 2212,7 @@ impl std::fmt::Display for DictPerError {
                got
            ),
            DictPerError::MalformedTableValueServingSizeUnitOfMeasureString { unit_of_measure } => format!(
                "Second element of `Food` instantiation input table `per` table keypair value list couldn’t be converted to UTF-8: {:?}",
                "Second element of `Food` instantiation input table `per` table keypair value list couldn't be converted to UTF-8: {:?}",
                unit_of_measure
            ),
            DictPerError::MissingTableValueServingSizeUnitOfMeasureString { got } => format!(

M src/food.rs => src/food.rs +1 -1
@@ 1163,7 1163,7 @@ fn serving_size_to_multiplier(serving_size: &ServingSizeish, food: &Food) -> Foo
        Food::Composite(composite) => match composite.serving_size()? {
            ServingSizeValue::Uni(uni) => serving_size.divide_by_serving_size(&uni),
            ServingSizeValue::Multi(mut multi) => {
                // Sum the reference `Composite` food’s serving size to create the
                // Sum the reference `Composite` food's serving size to create the
                // divisor.
                let init = multi.remove(0);
                let divisor = multi.into_iter().fold(init, |acc, serving_size| {

M src/food_error.rs => src/food_error.rs +2 -2
@@ 28,7 28,7 @@ pub enum FoodError {
        serving_sizeish: ServingSizeish,
    },

    /// Could not convert `per` table’s conversion factor to `Mass` or `Volume`.
    /// Could not convert `per` table's conversion factor to `Mass` or `Volume`.
    MalformedPerConversionFactor {
        conversion_factor: ServingSizeish,
    },


@@ 61,7 61,7 @@ impl std::fmt::Display for FoodError {
                serving_sizeish
            ),
            FoodError::MalformedPerConversionFactor { conversion_factor } => format!(
                "Could not convert `per` table’s conversion factor ({:?}) to `Mass` or `Volume`",
                "Could not convert `per` table's conversion factor ({:?}) to `Mass` or `Volume`",
                conversion_factor
            ),
            FoodError::InputFood(input_food_error) => {

M src/plan.rs => src/plan.rs +2 -2
@@ 28,8 28,8 @@ pub struct Plan {
    /// Basal Metabolic Rate
    /// --------------------
    ///
    /// Your *Basal Metabolic Rate* (BMR) is how many calories you’d burn each day if you
    /// did nothing but lie in bed. BMR doesn’t factor in calories burned from physical
    /// Your *Basal Metabolic Rate* (BMR) is how many calories you'd burn each day if you
    /// did nothing but lie in bed. BMR doesn't factor in calories burned from physical
    /// activity, the process of digestion, or things like walking from one room to
    /// another.
    pub bmr: f64,

M src/tir.rs => src/tir.rs +3 -3
@@ 143,7 143,7 @@ impl TryFrom<TirArgs> for Diet {
        // Improves Lua API ergonomics and error reporting.
        //
        // Stores internal `TirErrorKind` type rather than `rlua::Error` due to the
        // latter’s limited expressivity (string only).
        // latter's limited expressivity (string only).
        let mut errors: Option<Vec<TirErrorKind>> = None;

        let good_ip_dines: Option<Vec<Dine>> = process_tir_args(tir_args.0, &mut errors);


@@ 278,7 278,7 @@ fn partition_ip_dines_by_validity(
        ) = partition_dines_by_validity(ip_dines);

        let good_ip_dines = if good_ip_dines.len() > 0 {
            // Unwrap `Ok` from `good_ip_dines` elements, and drop count: we won’t be
            // Unwrap `Ok` from `good_ip_dines` elements, and drop count: we won't be
            // needing it any longer for error reporting.
            let good_ip_dines = good_ip_dines
                .into_iter()


@@ 347,7 347,7 @@ fn partition_dines_by_validity(

fn new_diet(
    good_ip_dines: Option<Vec<Dine>>,
    // We’ve already collected all errors detectable at a glance, e.g. erroneous and
    // We've already collected all errors detectable at a glance, e.g. erroneous and
    // unsupported input types. What errors remain will be missing data.
    mut errors: Option<Vec<TirErrorKind>>,
) -> TirResult<Diet> {

M src/tir_arg.rs => src/tir_arg.rs +1 -1
@@ 27,7 27,7 @@ pub enum TirArg {

    /// An unsupported value.
    ///
    /// The inner value is the unsupported value’s Lua type.
    /// The inner value is the unsupported value's Lua type.
    Unsupported(&'static str),
}


M src/tir_error.rs => src/tir_error.rs +1 -1
@@ 48,7 48,7 @@ impl TirError {
                .collect(),
        };

        // Anticipate rlua’s automatic insertion of “runtime error:”.
        // Anticipate rlua's automatic insertion of “runtime error:”.
        errors.insert(0, "Diet could not be instantiated".to_string());

        let errors = errors.join("\n\n");

M tests/data/complex/cfg/pantry/init.kiwi => tests/data/complex/cfg/pantry/init.kiwi +1 -1
@@ 133,7 133,7 @@
; - salt
(let [crimini-porcini-mushroom (food [crimini-mushroom porcini-mushroom])]
  (food umami-seasoning-blend
    "Trader Joe’s — Mushroom & Co — Umami Seasoning Blend"
    "Trader Joe's — Mushroom & Co — Umami Seasoning Blend"
    {:serving-size [12 :g]
     :source "portland product label"}
    {crimini-porcini-mushroom 0.05}

M tests/data/macros/cfg/pantry/init.fnl => tests/data/macros/cfg/pantry/init.fnl +1 -1
@@ 53,7 53,7 @@
   :per {:tbsp [6.9 :g]}})

(food umami-seasoning-blend
  "Trader Joe’s — Mushroom & Co — Umami Seasoning Blend"
  "Trader Joe's — Mushroom & Co — Umami Seasoning Blend"
  {:serving-size [100 :g]}
  [{onion-powder [1 :tbsp]} 1])


M tests/data/normal/dir/pantry/init.fnl => tests/data/normal/dir/pantry/init.fnl +1 -1
@@ 45,7 45,7 @@
   :per {:tbsp [6.9 :g]}}))

(local umami-seasoning-blend (food.new
  "Trader Joe’s — Mushroom & Co — Umami Seasoning Blend"
  "Trader Joe's — Mushroom & Co — Umami Seasoning Blend"
  {:serving-size [100 :g]}
  [{onion-powder [1 :tbsp]} 1]))


M tests/tests.rs => tests/tests.rs +2 -2
@@ 963,7 963,7 @@ fn complex_pantry_works() {

            let umami_seasoning_blend_docstring =
                <Food as Value>::docstring(&umami_seasoning_blend).expect("umami_seasoning_blend.docstring()");
            let umami_seasoning_blend_docstring_expected = "Trader Joe’s — Mushroom & Co — Umami Seasoning Blend".to_string();
            let umami_seasoning_blend_docstring_expected = "Trader Joe's — Mushroom & Co — Umami Seasoning Blend".to_string();
            let umami_seasoning_blend_docstring_expected = Some(umami_seasoning_blend_docstring_expected);
            assert_eq!(umami_seasoning_blend_docstring, umami_seasoning_blend_docstring_expected);



@@ 1041,7 1041,7 @@ fn complex_pantry_works() {
            lua_ctx
                .load(r#"local umami_seasoning_blend = pantry["umami-seasoning-blend"]
                         local umami_seasoning_blend_docstring = umami_seasoning_blend:docstring()
                         assert(umami_seasoning_blend_docstring == "Trader Joe’s — Mushroom & Co — Umami Seasoning Blend")
                         assert(umami_seasoning_blend_docstring == "Trader Joe's — Mushroom & Co — Umami Seasoning Blend")
                         local umami_seasoning_blend_aka = umami_seasoning_blend:aka()
                         assert(umami_seasoning_blend_aka == nil)
                         local umami_seasoning_blend_serving_size = umami_seasoning_blend:serving_size()