use toml::value;
pub struct Profile {
opt_level: OptLevel,
lto: Lto,
codegen_units: Option<u32>,
overflow_checks: bool,
panic: PanicStrategy,
}
impl Profile {
pub fn default_contract_release() -> Profile {
Profile {
opt_level: OptLevel::Z,
lto: Lto::Fat,
codegen_units: Some(1),
overflow_checks: true,
panic: PanicStrategy::Abort,
}
}
pub(super) fn merge(&self, profile: &mut value::Table) {
let mut set_value_if_vacant = |key: &'static str, value: value::Value| {
if !profile.contains_key(key) {
profile.insert(key.into(), value);
}
};
set_value_if_vacant("opt-level", self.opt_level.to_toml_value());
set_value_if_vacant("lto", self.lto.to_toml_value());
if let Some(codegen_units) = self.codegen_units {
set_value_if_vacant("codegen-units", codegen_units.into());
}
set_value_if_vacant("overflow-checks", self.overflow_checks.into());
set_value_if_vacant("panic", self.panic.to_toml_value());
}
}
#[allow(unused)]
#[derive(Clone, Copy)]
pub enum OptLevel {
NoOptimizations,
O1,
O2,
O3,
S,
Z,
}
impl OptLevel {
fn to_toml_value(self) -> value::Value {
match self {
OptLevel::NoOptimizations => 0.into(),
OptLevel::O1 => 1.into(),
OptLevel::O2 => 2.into(),
OptLevel::O3 => 3.into(),
OptLevel::S => "s".into(),
OptLevel::Z => "z".into(),
}
}
}
#[derive(Clone, Copy)]
#[allow(unused)]
pub enum Lto {
ThinLocal,
Fat,
Thin,
Off,
}
impl Lto {
fn to_toml_value(self) -> value::Value {
match self {
Lto::ThinLocal => false.into(),
Lto::Fat => "fat".into(),
Lto::Thin => "thin".into(),
Lto::Off => "off".into(),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
#[allow(unused)]
pub enum PanicStrategy {
Unwind,
Abort,
}
impl PanicStrategy {
fn to_toml_value(self) -> value::Value {
match self {
PanicStrategy::Unwind => "unwind".into(),
PanicStrategy::Abort => "abort".into(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn merge_profile_inserts_preferred_defaults() {
let profile = Profile::default_contract_release();
let manifest_toml = "";
let mut expected = toml::value::Table::new();
expected.insert("opt-level".into(), value::Value::String("z".into()));
expected.insert("lto".into(), value::Value::String("fat".into()));
expected.insert("codegen-units".into(), value::Value::Integer(1));
expected.insert("overflow-checks".into(), value::Value::Boolean(true));
expected.insert("panic".into(), value::Value::String("abort".into()));
let mut manifest_profile = toml::from_str(manifest_toml).unwrap();
profile.merge(&mut manifest_profile);
assert_eq!(expected, manifest_profile)
}
#[test]
fn merge_profile_preserves_user_defined_settings() {
let profile = Profile::default_contract_release();
let manifest_toml = r#"
panic = "unwind"
lto = false
opt-level = 3
overflow-checks = false
codegen-units = 256
"#;
let mut expected = toml::value::Table::new();
expected.insert("opt-level".into(), value::Value::Integer(3));
expected.insert("lto".into(), value::Value::Boolean(false));
expected.insert("codegen-units".into(), value::Value::Integer(256));
expected.insert("overflow-checks".into(), value::Value::Boolean(false));
expected.insert("panic".into(), value::Value::String("unwind".into()));
let mut manifest_profile = toml::from_str(manifest_toml).unwrap();
profile.merge(&mut manifest_profile);
assert_eq!(expected, manifest_profile)
}
}