1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::{
    loader::gnu_units,
    output::{QueryError, QueryReply},
    parsing::text_query,
    Context,
};

#[cfg(feature = "bundle-files")]
pub static DEFAULT_FILE: Option<&'static str> = Some(include_str!("../definitions.units"));
#[cfg(not(feature = "bundle-files"))]
pub static DEFAULT_FILE: Option<&'static str> = None;

#[cfg(feature = "bundle-files")]
pub static DATES_FILE: Option<&'static str> = Some(include_str!("../datepatterns.txt"));
#[cfg(not(feature = "bundle-files"))]
pub static DATES_FILE: Option<&'static str> = None;

#[cfg(feature = "bundle-files")]
pub static CURRENCY_FILE: Option<&'static str> = Some(include_str!("../currency.units"));
#[cfg(not(feature = "bundle-files"))]
pub static CURRENCY_FILE: Option<&'static str> = None;

pub fn eval(ctx: &mut Context, line: &str) -> Result<QueryReply, QueryError> {
    ctx.update_time();
    let mut iter = text_query::TokenIterator::new(line.trim()).peekable();
    let expr = text_query::parse_query(&mut iter);
    let res = ctx.eval_query(&expr)?;
    if ctx.save_previous_result {
        if let QueryReply::Number(ref number_parts) = res {
            if let Some(ref raw) = number_parts.raw_value {
                ctx.previous_result = Some(raw.clone());
            }
        }
    }
    Ok(res)
}

/// A version of eval() that converts results and errors into strings.
pub fn one_line(ctx: &mut Context, line: &str) -> Result<String, String> {
    eval(ctx, line)
        .as_ref()
        .map(ToString::to_string)
        .map_err(ToString::to_string)
}

/// Tries to create a context that has core definitions only (contents
/// of definitions.units), will fail if the bundle-files feature isn't enabled.
/// Mainly intended for unit testing.
pub fn simple_context() -> Result<Context, String> {
    let message = "bundle-files feature not enabled, cannot create simple context.";

    let units = DEFAULT_FILE.ok_or(message.to_owned())?;
    let mut iter = gnu_units::TokenIterator::new(&*units).peekable();
    let units = gnu_units::parse(&mut iter);

    let dates = DATES_FILE.ok_or(message.to_owned())?;
    let dates = crate::parsing::datetime::parse_datefile(dates);

    let mut ctx = Context::new();
    ctx.load(units)?;
    ctx.load_dates(dates);

    Ok(ctx)
}

// Returns `env!("CARGO_PKG_VERSION")`, a string in `x.y.z` format.
pub fn version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}