use std::fmt;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
pub trait Labeled {
fn add_label(&mut self, label: &str) -> Result<(), ()>;
fn get_labels(&self) -> &[String];
}
pub trait Offset {
fn get_offset(&self) -> usize;
}
#[derive(Debug, Clone)]
pub struct DTInfo {
pub reserve_info: Vec<ReserveInfo>,
pub boot_cpuid: u32,
pub root: Node,
}
impl DTInfo {
pub fn apply_amends(&self, amends: &[Node]) -> Self {
let mut new_tree: DTInfo = self.clone();
new_tree.merge_amends(amends);
new_tree
}
pub fn merge_amends(&mut self, amends: &[Node]) {
for a in amends {
match a.name() {
&NodeName::Ref(ref refr) => {
if refr.starts_with('/') {
self.get_node_by_path_mut(refr).unwrap().merge(a)
} else {
self.find_node_by_label_mut(refr).unwrap().merge(a)
};
}
&NodeName::Full(_) => {
self.root.merge(a)
}
}
}
}
pub fn get_node_by_path<'a>(&'a self, path: &str) -> Result<&'a Node, ()> {
fn internal<'a>(node: &'a Node, path: &str) -> Result<&'a Node, ()> {
if path.is_empty() {
return Err(())
}
let (name, rem) = path.find('/')
.and_then(|pos| Some(path.split_at(pos)))
.and_then(|(a,b)| Some((a, Some(b))))
.unwrap_or((path, None));
let subnode = match *node {
Node::Deleted{..} => return Err(()),
Node::Existing{ref children, ..} => children.get(name)
};
match subnode {
None => Err(()),
Some(subnode) =>
match rem {
None => Ok(subnode),
Some(path) => internal(subnode, path),
},
}
}
if !path.starts_with('/') {
Err(())
} else if path == "/" {
Ok(&self.root)
} else {
internal(&self.root, &path[1..])
}
}
pub fn get_node_by_path_mut<'a>(&'a mut self, path: &str) -> Result<&'a mut Node, ()> {
fn internal<'a>(node: &'a mut Node, path: &str) -> Result<&'a mut Node, ()> {
if path.is_empty() {
return Err(())
}
let (name, rem) = path.find('/')
.and_then(|pos| Some(path.split_at(pos)))
.and_then(|(a,b)| Some((a, Some(b))))
.unwrap_or((path, None));
let subnode = match *node {
Node::Deleted{..} => return Err(()),
Node::Existing{ref mut children, ..} => children.get_mut(name)
};
match subnode {
None => Err(()),
Some(subnode) =>
match rem {
None => Ok(subnode),
Some(path) => internal(subnode, path),
},
}
}
if !path.starts_with('/') {
Err(())
} else if path == "/" {
Ok(&mut self.root)
} else {
internal(&mut self.root, &path[1..])
}
}
pub fn find_node_by_label<'a>(&'a self, label: &str) -> Result<&'a Node, ()> {
fn internal<'a>(node: &'a Node, label: &str) -> Result<&'a Node, ()> {
match *node {
Node::Deleted { .. } => Err(()),
Node::Existing { ref labels, ref children, .. } => {
if labels.iter().map(|s| s.as_str()).any(|l| l == label) {
Ok(node)
} else {
for child in children.values() {
if let Ok(node) = internal(child, label) {
return Ok(node)
}
}
Err(())
}
}
}
}
if label.is_empty() {
Err(())
} else {
internal(&self.root, label)
}
}
pub fn find_node_by_label_mut<'a>(&'a mut self, label: &str) -> Result<&'a mut Node, ()> {
fn internal<'a>(node: &'a mut Node, label: &str) -> Result<&'a mut Node, ()> {
if node.get_labels().iter().map(|s| s.as_str()).any(|l| l == label) {
return Ok(node)
}
match *node {
Node::Deleted { .. } => Err(()),
Node::Existing { ref mut children, .. } => {
for child in children.values_mut() {
if let Ok(node) = internal(child, label) {
return Ok(node)
}
}
Err(())
}
}
}
if label.is_empty() {
Err(())
} else {
internal(&mut self.root, label)
}
}
}
#[derive(Debug, Clone)]
pub struct ReserveInfo {
pub address: u64,
pub size: u64,
pub labels: Vec<String>,
}
impl Labeled for ReserveInfo {
fn add_label(&mut self, label: &str) -> Result<(), ()> {
let label = label.to_owned();
if !self.labels.contains(&label) {
self.labels.push(label);
}
Ok(())
}
fn get_labels(&self) -> &[String] {
&self.labels
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Node {
Deleted {
name: NodeName,
offset: usize
},
Existing {
name: NodeName,
proplist: HashMap<String, Property>,
children: HashMap<String, Node>,
labels: Vec<String>,
offset: usize,
},
}
impl Node {
pub fn name(&self) -> &NodeName {
match *self {
Node::Deleted { ref name, .. } |
Node::Existing { ref name, .. } => name,
}
}
fn merge(&mut self, other: &Node) {
match (self, other) {
(&mut Node::Existing { proplist: ref mut s_props,
children: ref mut s_childs,
labels: ref mut s_labels,
.. },
&Node::Existing { proplist: ref o_props,
children: ref o_childs,
labels: ref o_labels,
.. }) => {
s_props.extend(o_props.iter().map(|(k, v)| (k.to_owned(), v.to_owned())));
for (name, node) in o_childs {
match node {
&Node::Deleted { .. } => { s_childs.remove(name).expect(&format!("Deleted non-existent node {}", name)); } &Node::Existing { .. } => {
let entry = s_childs.entry(name.to_owned());
if let Entry::Occupied(mut e) = entry {
e.get_mut().merge(node);
} else {
entry.or_insert_with(|| node.clone());
}
}
}
}
s_labels.extend(o_labels.iter().map(|s| s.to_owned()));
s_labels.sort();
s_labels.dedup();
}
_ => unreachable!()
}
}
}
impl Labeled for Node {
fn add_label(&mut self, label: &str) -> Result<(), ()> {
match *self {
Node::Deleted { .. } => Err(()),
Node::Existing { ref mut labels, .. } => {
let label = label.to_owned();
if labels.contains(&label) {
labels.push(label);
}
Ok(())
}
}
}
fn get_labels(&self) -> &[String] {
match *self {
Node::Deleted { .. } => &[],
Node::Existing { ref labels, .. } => labels,
}
}
}
impl Offset for Node {
fn get_offset(&self) -> usize {
match *self {
Node::Deleted { offset, .. } |
Node::Existing { offset, .. } => offset,
}
}
}
impl fmt::Display for Node {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Node::Deleted { ref name, .. } => write!(f, "// Node {} deleted", name)?,
Node::Existing { ref name, ref proplist, ref children, .. } => {
writeln!(f, "{} {{", name)?;
for prop in proplist.values() {
writeln!(f, " {}", prop)?;
}
for node in children.values() {
match *node {
Node::Deleted { ref name, .. } => {
writeln!(f, " // Node {} deleted", name)?
}
Node::Existing { ref name, .. } => writeln!(f, " {} {{ ... }}", name)?,
}
}
write!(f, "}}")?;
}
}
Ok(())
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum NodeName {
Ref(String),
Full(String),
}
impl fmt::Display for NodeName {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
NodeName::Ref(ref name) |
NodeName::Full(ref name) => write!(f, "{}", name),
}
}
}
impl NodeName {
pub fn as_str(&self) -> &str {
match *self {
NodeName::Ref(ref name) |
NodeName::Full(ref name) => name,
}
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Property {
Deleted {
name: String,
offset: usize
},
Existing {
name: String,
val: Option<Vec<Data>>,
labels: Vec<String>,
offset: usize,
},
}
impl Property {
pub fn name(&self) -> &str {
match *self {
Property::Deleted{ref name, ..} |
Property::Existing{ref name, ..} => name
}
}
}
impl Labeled for Property {
fn add_label(&mut self, label: &str) -> Result<(), ()> {
match *self {
Property::Deleted { .. } => Err(()),
Property::Existing { ref mut labels, .. } => {
let label = label.to_owned();
if labels.contains(&label) {
labels.push(label);
}
Ok(())
}
}
}
fn get_labels(&self) -> &[String] {
match *self {
Property::Deleted { .. } => &[],
Property::Existing { ref labels, .. } => labels,
}
}
}
impl Offset for Property {
fn get_offset(&self) -> usize {
match *self {
Property::Deleted { offset, .. } |
Property::Existing { offset, .. } => offset,
}
}
}
impl fmt::Display for Property {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Property::Deleted { ref name, .. } => write!(f, "// Property {} deleted", name)?,
Property::Existing { ref name, ref val, .. } => {
write!(f, "{}", name)?;
if let Some(ref data) = *val {
if !data.is_empty() {
let mut iter = data.iter();
write!(f, " = {}", iter.next().unwrap())?;
for d in iter {
write!(f, ", {}", d)?;
}
}
}
write!(f, ";")?;
}
}
Ok(())
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Data {
Reference(String, Option<u64>),
String(String),
Cells(usize, Vec<Cell>),
ByteArray(Vec<u8>),
}
impl fmt::Display for Data {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Data::Reference(ref r, _) => write!(f, "&{}", r)?,
Data::String(ref s) => write!(f, "{}", s)?,
Data::Cells(bits, ref cells) => {
if bits != 32 {
write!(f, "/bits/ {}", bits)?;
}
write!(f, "<")?;
if !cells.is_empty() {
let mut iter = cells.iter();
write!(f, "{}", iter.next().unwrap())?;
for c in iter {
write!(f, "{}", c)?;
}
}
write!(f, ">")?;
}
Data::ByteArray(ref arr) => {
write!(f, "[ ")?;
if !arr.is_empty() {
let mut iter = arr.iter();
write!(f, "{:02X}", iter.next().unwrap())?;
for d in iter {
write!(f, " {:02X}", d)?;
}
}
write!(f, " ]")?;
}
}
Ok(())
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Cell {
Num(u64),
Ref(String, Option<u64>),
}
impl fmt::Display for Cell {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Cell::Num(i) => write!(f, "{}", i)?,
Cell::Ref(ref s, _) => write!(f, "&{}", s)?,
}
Ok(())
}
}