pumpkin_solver/statistics/
statistic_logging.rs

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
//! Responsible for behaviour related to logging statistics with a specific pre-fix and closing
//! lines.

use std::fmt::Display;
use std::sync::OnceLock;

use convert_case::Case;
use convert_case::Casing;

/// The options for statistic logging containing the statistic prefix, the (optional) line which is
/// printed after the statistics, and the (optional) casing of the statistics.
#[derive(Debug)]
pub struct StatisticOptions<'a> {
    // What is printed before a statistic is printed, the statistics will be printed in the
    // form `{PREFIX} {VALUE}={NAME}`
    statistic_prefix: &'a str,
    // A closing line which is printed after all of the statistics have been printed
    after_statistics: Option<&'a str>,
    // The casing of the name of the statistic
    statistics_casing: Option<Case>,
}

static STATISTIC_OPTIONS: OnceLock<StatisticOptions> = OnceLock::new();

/// Configures the logging of the statistics.
///
/// It specifies the (optional) prefix and a closing line (postfix) which
/// can be printed after all of the statistics have been logged. Statistics will only be printed
/// if `log_statistics` is true.
pub fn configure_statistic_logging(
    prefix: &'static str,
    after: Option<&'static str>,
    casing: Option<Case>,
) {
    let _ = STATISTIC_OPTIONS.get_or_init(|| StatisticOptions {
        statistic_prefix: prefix,
        after_statistics: after,
        statistics_casing: casing,
    });
}

/// Logs the provided statistic with name `name` and value `value`. At the moment it will log in
/// the format `STATISTIC_PREFIX NAME=VALUE`.
pub fn log_statistic(name: impl Display, value: impl Display) {
    if let Some(statistic_options) = STATISTIC_OPTIONS.get() {
        let name = if let Some(casing) = &statistic_options.statistics_casing {
            name.to_string().to_case(*casing)
        } else {
            name.to_string()
        };
        println!("{} {name}={value}", statistic_options.statistic_prefix)
    }
}

/// Logs the postfix of the statistics (if it has been set).
///
/// Certain formats (e.g. the [MiniZinc](https://www.minizinc.org/doc-2.7.6/en/fzn-spec.html#statistics-output)
/// output format) require that a block of statistics is followed by a closing line; this
/// function outputs this closing line **if** it is configued.
pub fn log_statistic_postfix() {
    if let Some(statistic_options) = STATISTIC_OPTIONS.get() {
        if let Some(post_fix) = statistic_options.after_statistics {
            println!("{post_fix}")
        }
    }
}

/// Returns whether or not statistics should be logged by determining whether the
/// [`StatisticOptions`] have been configured.
pub fn should_log_statistics() -> bool {
    STATISTIC_OPTIONS.get().is_some()
}