use crate::{
MontyObject,
args::ArgValues,
bytecode::{CallResult, VM},
exception_private::{ExcType, RunResult},
heap::{HeapData, HeapId},
intern::StaticStrings,
modules::ModuleFunctions,
os::{GetenvArgs, OsFunctionCall},
resource::{ResourceError, ResourceTracker},
types::{Module, Property, property::ZeroArgOsProperty},
value::Value,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum::Display, serde::Serialize, serde::Deserialize)]
#[strum(serialize_all = "lowercase")]
pub(crate) enum OsFunctions {
Getenv,
}
pub fn create_module(vm: &mut VM<'_, impl ResourceTracker>) -> Result<HeapId, ResourceError> {
let mut module = Module::new(StaticStrings::Os);
module.set_attr(
StaticStrings::Getenv,
Value::ModuleFunction(ModuleFunctions::Os(OsFunctions::Getenv)),
vm,
);
module.set_attr(
StaticStrings::Environ,
Value::Property(Property::Os(ZeroArgOsProperty::GetEnviron)),
vm,
);
vm.heap.allocate(HeapData::Module(module))
}
pub(super) fn call(
vm: &mut VM<'_, impl ResourceTracker>,
functions: OsFunctions,
args: ArgValues,
) -> RunResult<CallResult> {
match functions {
OsFunctions::Getenv => getenv(vm, args),
}
}
fn getenv(vm: &mut VM<'_, impl ResourceTracker>, args: ArgValues) -> RunResult<CallResult> {
let (key_value, default_value) = args.get_one_two_args("os.getenv", vm.heap)?;
if let Some(key) = key_value.as_either_str(vm.heap) {
key_value.drop_with_heap(vm.heap);
Ok(CallResult::OsCall(OsFunctionCall::Getenv(GetenvArgs {
key: key.into_string(vm.interns),
default: MontyObject::new(default_value.unwrap_or(Value::None), vm),
})))
} else {
let type_name = key_value.py_type_name_heap(vm.heap, vm.interns);
key_value.drop_with_heap(vm.heap);
if let Some(d) = default_value {
d.drop_with_heap(vm.heap);
}
Err(ExcType::type_error(format!("str expected, not {type_name}")))
}
}