pub trait Application {
fn new(name: &str, parameters: &[Parameter]) -> Self;
fn get_name(&self) -> &str;
fn tick(&mut self) -> bool;
}
pub struct BaseApplication {
name: String,
parameters: Vec<Parameter>,
pub(crate) frame_allocator: bumpalo::Bump,
}
impl Application for BaseApplication {
fn new(name: &str, parameters: &[Parameter]) -> BaseApplication {
env_logger::init();
let mut parameters = parameters.to_vec();
for (key, value) in std::env::vars().filter(|(key, _)| key.as_str().starts_with("BE_")) {
upsert_parameter(
&mut parameters,
Parameter::new_string(
key.trim_start_matches("BE_").to_string().replace('_', "-").to_lowercase(),
value,
),
);
}
for argument in std::env::args().filter(|argument| argument.starts_with("--")) {
upsert_parameter(&mut parameters, parse_argument(&argument).unwrap());
}
let application = BaseApplication {
name: String::from(name),
parameters,
frame_allocator: bumpalo::Bump::with_capacity(1024 * 1024 * 32), };
if let Some(e) = application.get_parameter("log.level") {
let level = match e.value.as_str() {
"trace" => log::LevelFilter::Trace,
"debug" => log::LevelFilter::Debug,
"info" => log::LevelFilter::Info,
"warn" => log::LevelFilter::Warn,
"error" => log::LevelFilter::Error,
"off" => log::LevelFilter::Off,
_ => log::LevelFilter::Off,
};
log::set_max_level(level);
}
if application.get_parameter("trace").is_some() {
let _ = tracing_subscriber::fmt().with_max_level(tracing::Level::DEBUG).try_init();
}
info!("Byte-Engine");
info!(
"Initializing \x1b[4m{}\x1b[24m application with parameters: {}.",
name,
application
.parameters
.iter()
.map(|p| format!("{}={}", p.name, p.value))
.collect::<Vec<String>>()
.join(", ")
);
trace!("Initialized base Byte-Engine application!");
application
}
fn tick(&mut self) -> bool {
true
}
fn get_name(&self) -> &str {
&self.name
}
}
impl Parameters for BaseApplication {
fn get_parameter(&self, name: &str) -> Option<&Parameter> {
self.parameters.iter().find(|p| p.name == name)
}
}
impl BaseApplication {
pub(crate) fn parameters(&self) -> &[Parameter] {
&self.parameters
}
}
fn upsert_parameter(parameters: &mut Vec<Parameter>, parameter: Parameter) {
if let Some(existing) = parameters.iter_mut().find(|existing| existing.name == parameter.name) {
*existing = parameter;
} else {
parameters.push(parameter);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_base_application() {
let app = BaseApplication::new("Test", &[]);
assert!(app.get_name() == "Test");
}
#[test]
fn upsert_parameter_replaces_value_with_same_name() {
let mut parameters = vec![Parameter::new("render.debug.extended", "true")];
upsert_parameter(&mut parameters, Parameter::new("render.debug.extended", "false"));
assert_eq!(parameters.len(), 1);
assert_eq!(parameters[0].value(), "false");
}
}
use log::{info, trace};
use super::Parameter;
use crate::application::parameters::{parse_argument, Parameters};