1use alloc::string::String;
7use alloc::vec::Vec;
8use serde::Deserialize;
9
10use crate::core::bootables::{BootTarget, GenericBootTarget};
11#[cfg(feature = "iso")]
12use crate::iso::IsoBootTarget;
13
14#[derive(Debug, Deserialize)]
16#[serde(tag = "type", rename_all = "snake_case")]
17pub enum TargetConfig {
18 Generic {
20 label: String,
22 executable: String,
24 #[serde(default)]
26 options: String,
27 },
28
29 #[cfg(feature = "iso")]
31 Iso {
32 label: String,
34
35 iso_path: String,
37
38 executable: Option<String>,
41
42 #[serde(default)]
44 options: String,
45 },
46}
47
48impl TargetConfig {
49 fn into_boot_target(self) -> BootTarget {
50 match self {
51 TargetConfig::Generic {
52 label,
53 executable,
54 options,
55 } => BootTarget::Generic(GenericBootTarget::new(label, executable, options)),
56 #[cfg(feature = "iso")]
57 TargetConfig::Iso {
58 label,
59 iso_path,
60 executable,
61 options,
62 } => BootTarget::Iso(IsoBootTarget {
63 label,
64 iso_path,
65 executable,
66 options,
67 }),
68 }
69 }
70}
71
72#[derive(Debug, Deserialize)]
74pub struct Config {
75 pub boot_targets: Vec<TargetConfig>,
77}
78
79impl Config {
80 pub fn load_from_file(path: &str) -> Result<Self, ConfigError> {
82 let contents = read_file_to_string(path)?;
84
85 let config: Config = toml::from_str(&contents).map_err(|e| {
87 log::error!("TOML parse error: {:?}", e);
88 ConfigError::ParseError
89 })?;
90
91 Ok(config)
92 }
93
94 pub fn into_boot_targets(self) -> Vec<BootTarget> {
96 self.boot_targets
97 .into_iter()
98 .map(|target| target.into_boot_target())
99 .collect()
100 }
101}
102
103fn read_file_to_string(path: &str) -> Result<String, ConfigError> {
105 use uefi::CString16;
106 use uefi::fs::FileSystem;
107
108 let path_cstr = CString16::try_from(path).map_err(|_| ConfigError::InvalidPath)?;
110
111 let mut fs = FileSystem::new(
113 uefi::boot::get_image_file_system(uefi::boot::image_handle())
114 .map_err(|_| ConfigError::FsError)?,
115 );
116
117 let buf = fs
119 .read(path_cstr.as_ref())
120 .map_err(|_| ConfigError::FileNotFound)?;
121
122 String::from_utf8(buf).map_err(|_| ConfigError::EncodingError)
124}
125
126#[derive(Debug)]
128pub enum ConfigError {
129 InvalidPath,
131 FileNotFound,
133 FsError,
135 EncodingError,
137 ParseError,
139}
140
141impl core::fmt::Display for ConfigError {
142 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
143 match self {
144 ConfigError::InvalidPath => write!(f, "Invalid file path"),
145 ConfigError::FileNotFound => write!(f, "Config file not found"),
146 ConfigError::FsError => write!(f, "Filesystem error"),
147 ConfigError::EncodingError => write!(f, "File encoding error"),
148 ConfigError::ParseError => write!(f, "TOML parse error"),
149 }
150 }
151}