pub mod hob;
mod metadata;
pub mod params;
pub mod service;
mod storage;
mod struct_component;
mod type_name;
use crate::error::Result;
pub use metadata::MetaData;
pub use storage::{Storage, UnsafeStorageCell};
#[doc(hidden)]
pub use struct_component::StructComponent;
pub use patina_macro::component;
pub trait Component {
unsafe fn run_unsafe(&mut self, storage: storage::UnsafeStorageCell) -> Result<bool>;
fn run(&mut self, storage: &mut storage::Storage) -> Result<bool> {
storage.apply_deferred();
let storage_cell = storage::UnsafeStorageCell::from(storage);
unsafe { self.run_unsafe(storage_cell) }
}
fn initialize(&mut self, storage: &mut storage::Storage) -> bool;
fn metadata(&self) -> &metadata::MetaData;
}
pub trait IntoComponent<Input> {
fn into_component(self) -> alloc::boxed::Box<dyn Component>;
}
pub mod prelude {
pub use crate::{
component::{
IntoComponent,
hob::{FromHob, Hob},
params::{Commands, Config, ConfigMut, Handle},
service::{IntoService, Service},
},
error::{EfiError, Result},
};
}
#[cfg(test)]
#[coverage(off)]
mod tests {
extern crate std;
use super::*;
use crate as patina;
use crate::{
BinaryGuid,
component::{
component,
hob::{FromHob, Hob},
params::ConfigMut,
},
error::{EfiError, Result},
};
struct ComponentSuccess;
#[component]
impl ComponentSuccess {
fn entry_point(self) -> Result<()> {
Ok(())
}
}
struct ComponentNotDispatchedConfig;
#[component]
impl ComponentNotDispatchedConfig {
fn entry_point(self, _: ConfigMut<u32>) -> Result<()> {
Ok(())
}
}
struct ComponentFail;
#[component]
impl ComponentFail {
fn entry_point(self) -> Result<()> {
Err(EfiError::Aborted)
}
}
#[derive(FromHob, zerocopy_derive::FromBytes)]
#[hob = "d4ffc718-fb82-4274-9afc-aa8b1eef5293"]
#[repr(C)]
pub struct TestHob;
struct ComponentHobDep1;
#[component]
impl ComponentHobDep1 {
fn entry_point(self, _hob: Hob<TestHob>) -> Result<()> {
Ok(())
}
}
#[derive(FromHob, zerocopy_derive::FromBytes)]
#[hob = "d4ffc718-fb82-4274-9afc-aa8b1eef5293"]
#[repr(C)]
pub struct TestHob2;
struct ComponentHobDep2;
#[component]
impl ComponentHobDep2 {
fn entry_point(self, _hob: Hob<TestHob2>) -> Result<()> {
Ok(())
}
}
struct ComponentHobDep3;
#[component]
impl ComponentHobDep3 {
fn entry_point(self, _hob: Hob<TestHob2>) -> Result<()> {
Ok(())
}
}
#[test]
fn test_component_run_return_handling() {
const HOB_GUID: BinaryGuid = BinaryGuid::from_string("D4FFC718-FB82-4274-9AFC-AA8B1EEF5293");
let mut storage = storage::Storage::new();
let mut component1 = ComponentSuccess.into_component();
component1.initialize(&mut storage);
assert!(component1.run(&mut storage).is_ok_and(|res| res));
let mut component2 = ComponentNotDispatchedConfig.into_component();
component2.initialize(&mut storage);
storage.lock_configs(); assert!(component2.run(&mut storage).is_ok_and(|res| !res));
let mut component3 = ComponentFail.into_component();
component3.initialize(&mut storage);
assert!(component3.run(&mut storage).is_err_and(|res| res == EfiError::Aborted));
let mut component4 = ComponentHobDep1.into_component();
component4.initialize(&mut storage);
assert!(component4.run(&mut storage).is_ok_and(|res| !res));
let mut component5 = ComponentHobDep2.into_component();
component5.initialize(&mut storage);
assert!(component5.run(&mut storage).is_ok_and(|res| !res));
let mut component6 = ComponentHobDep3.into_component();
component6.initialize(&mut storage);
assert!(component6.run(&mut storage).is_ok_and(|res| !res));
storage.register_hob::<TestHob>();
assert!(storage.get_hob::<TestHob>().is_none());
assert!(storage.get_hob_parsers(&HOB_GUID).len() == 2);
storage.add_hob(TestHob);
assert!(storage.get_hob::<TestHob>().is_some());
assert_eq!(storage.get_hob::<TestHob>().unwrap().iter().count(), 1);
storage.add_hob(TestHob2);
assert!(storage.get_hob::<TestHob2>().is_some());
assert_eq!(storage.get_hob::<TestHob2>().unwrap().iter().count(), 1);
assert!(component4.run(&mut storage).is_ok_and(|res| res));
assert!(component5.run(&mut storage).is_ok_and(|res| res));
assert!(component6.run(&mut storage).is_ok_and(|res| res));
}
}