use super::{FallibleNode, Node};
use crate::{
helpers::{FallibleParser, FallibleRoot},
parsing::{aligned::AlignedParser, Panic, ParseError, ParserWithMode},
FdtError,
};
pub struct Chosen<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
pub(crate) node: FallibleNode<'a, P>,
}
impl<'a, P: ParserWithMode<'a>> Chosen<'a, P> {
#[track_caller]
pub fn bootargs(self) -> P::Output<Option<&'a str>> {
P::to_output(crate::tryblock!({
for prop in self.node.properties()?.into_iter().flatten() {
if prop.name == "bootargs" {
return Ok(Some(
core::str::from_utf8(&prop.value[..prop.value.len() - 1])
.map_err(|_| FdtError::ParseError(ParseError::InvalidCStrValue))?,
));
}
}
Ok(None)
}))
}
#[allow(clippy::type_complexity)]
#[track_caller]
pub fn stdout(self) -> P::Output<Option<Stdout<'a, P>>> {
P::to_output(crate::tryblock!({
let this: Chosen<'a, FallibleParser<'a, P>> = Chosen { node: self.node };
let Some(stdout) = this.stdout_path()? else { return Ok(None) };
let root: FallibleRoot<'a, P> = this.node.make_root()?;
let node = match stdout.path().contains('/') {
true => root.find_node(stdout.path())?,
false => None,
};
match node {
Some(node) => Ok(Some(Stdout { node: node.alt(), params: stdout.params() })),
None => {
let Some(aliases) = root.aliases()? else { return Ok(None) };
match aliases.resolve(stdout.path())? {
Some(node) => Ok(Some(Stdout { node: node.alt(), params: stdout.params() })),
None => Ok(None),
}
}
}
}))
}
#[track_caller]
pub fn stdout_path(self) -> P::Output<Option<StdInOutPath<'a>>> {
P::to_output(crate::tryblock!({
self.node
.properties()?
.into_iter()
.find_map(|n| match n {
Err(e) => Some(Err(e)),
Ok(property) => match property.name == "stdout-path" {
false => None,
true => Some(property.as_value::<&'a str>().map_err(Into::into).map(|s| {
let (path, params) =
s.split_once(':').map_or_else(|| (s, None), |(name, params)| (name, Some(params)));
StdInOutPath { path, params }
})),
},
})
.transpose()
}))
}
#[allow(clippy::type_complexity)]
#[track_caller]
pub fn stdin(self) -> P::Output<Option<Stdin<'a, P>>> {
P::to_output(crate::tryblock!({
let this: Chosen<'a, FallibleParser<'a, P>> = Chosen { node: self.node };
let Some(stdin) = this.stdin_path()? else { return Ok(None) };
let root: FallibleRoot<'a, P> = this.node.make_root()?;
let node = match stdin.path().contains('/') {
true => root.find_node(stdin.path())?,
false => None,
};
match node {
Some(node) => Ok(Some(Stdin { node: node.alt(), params: stdin.params() })),
None => {
let Some(aliases) = root.aliases()? else { return Ok(None) };
match aliases.resolve(stdin.path())? {
Some(node) => Ok(Some(Stdin { node: node.alt(), params: stdin.params() })),
None => Ok(None),
}
}
}
}))
}
#[track_caller]
pub fn stdin_path(self) -> P::Output<Option<StdInOutPath<'a>>> {
P::to_output(crate::tryblock!({
self.node
.properties()?
.into_iter()
.find_map(|n| match n {
Err(e) => Some(Err(e)),
Ok(property) => match property.name == "stdin-path" {
false => None,
true => Some(property.as_value::<&str>().map_err(Into::into).map(|s| {
let (path, params) =
s.split_once(':').map_or_else(|| (s, None), |(name, params)| (name, Some(params)));
StdInOutPath { path, params }
})),
},
})
.transpose()
}))
}
}
impl<'a, P: ParserWithMode<'a>> Clone for Chosen<'a, P> {
fn clone(&self) -> Self {
*self
}
}
impl<'a, P: ParserWithMode<'a>> Copy for Chosen<'a, P> {}
pub struct Stdin<'a, P: ParserWithMode<'a>> {
pub node: Node<'a, P>,
pub params: Option<&'a str>,
}
impl<'a, P: ParserWithMode<'a>> core::fmt::Debug for Stdin<'a, P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut debug_struct = f.debug_struct("Stdin");
let debug_struct = match self.node.fallible().name() {
Ok(name) => debug_struct.field("node", &name),
Err(e) => debug_struct.field("node", &Err::<(), _>(e)),
};
debug_struct.field("params", &self.params).finish()
}
}
pub struct Stdout<'a, P: ParserWithMode<'a>> {
pub node: Node<'a, P>,
pub params: Option<&'a str>,
}
impl<'a, P: ParserWithMode<'a>> core::fmt::Debug for Stdout<'a, P> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut debug_struct = f.debug_struct("Stdin");
let debug_struct = match self.node.fallible().name() {
Ok(name) => debug_struct.field("node", &name),
Err(e) => debug_struct.field("node", &Err::<(), _>(e)),
};
debug_struct.field("params", &self.params).finish()
}
}
pub struct StdInOutPath<'a> {
path: &'a str,
params: Option<&'a str>,
}
impl<'a> StdInOutPath<'a> {
pub fn path(&self) -> &'a str {
self.path
}
pub fn params(&self) -> Option<&'a str> {
self.params
}
}