Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ unproven = []
[dependencies]
either = "1.5"
xmltree = "0.8"
failure = "0.1"
anyhow = "1.0.19"
thiserror = "1.0.5"

[dependencies.serde]
version = "1.0"
Expand Down
37 changes: 17 additions & 20 deletions src/elementext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,24 @@
use xmltree::Element;

use crate::types::{BoolParse, Parse};
use failure::ResultExt;

use crate::error::*;

/// Defines extensions for implementation over xmltree::Element
pub trait ElementExt {
fn get_child_text_opt<K>(&self, k: K) -> Result<Option<String>, SVDError>
fn get_child_text_opt<K>(&self, k: K) -> Result<Option<String>>
where
String: PartialEq<K>;
fn get_child_text<K>(&self, k: K) -> Result<String, SVDError>
fn get_child_text<K>(&self, k: K) -> Result<String>
where
String: PartialEq<K>,
K: core::fmt::Display + Clone;

fn get_text(&self) -> Result<String, SVDError>;
fn get_text(&self) -> Result<String>;

fn get_child_elem<'a>(&'a self, n: &str) -> Result<&'a Element, SVDError>;
fn get_child_u32(&self, n: &str) -> Result<u32, SVDError>;
fn get_child_bool(&self, n: &str) -> Result<bool, SVDError>;
fn get_child_elem<'a>(&'a self, n: &str) -> Result<&'a Element>;
fn get_child_u32(&self, n: &str) -> Result<u32>;
fn get_child_bool(&self, n: &str) -> Result<bool>;

fn merge(&self, n: &Self) -> Self;

Expand All @@ -31,7 +30,7 @@ pub trait ElementExt {

/// Implements extensions for xmltree::Element
impl ElementExt for Element {
fn get_child_text_opt<K>(&self, k: K) -> Result<Option<String>, SVDError>
fn get_child_text_opt<K>(&self, k: K) -> Result<Option<String>>
where
String: PartialEq<K>,
{
Expand All @@ -41,44 +40,42 @@ impl ElementExt for Element {
Ok(None)
}
}
fn get_child_text<K>(&self, k: K) -> Result<String, SVDError>
fn get_child_text<K>(&self, k: K) -> Result<String>
where
String: PartialEq<K>,
K: core::fmt::Display + Clone,
{
self.get_child_text_opt(k.clone())?
.ok_or_else(|| SVDErrorKind::MissingTag(self.clone(), format!("{}", k)).into())
.ok_or_else(|| SVDError::MissingTag(self.clone(), format!("{}", k)).into())
}

/// Get text contained by an XML Element
fn get_text(&self) -> Result<String, SVDError> {
fn get_text(&self) -> Result<String> {
match self.text.as_ref() {
Some(s) => Ok(s.clone()),
// FIXME: Doesn't look good because SVDErrorKind doesn't format by itself. We already
// FIXME: Doesn't look good because SVDError doesn't format by itself. We already
// capture the element and this information can be used for getting the name
// This would fix ParseError
None => Err(SVDErrorKind::EmptyTag(self.clone(), self.name.clone()).into()),
None => Err(SVDError::EmptyTag(self.clone(), self.name.clone()).into()),
}
}

/// Get a named child element from an XML Element
fn get_child_elem<'a>(&'a self, n: &str) -> Result<&'a Element, SVDError> {
fn get_child_elem<'a>(&'a self, n: &str) -> Result<&'a Element> {
match self.get_child(n) {
Some(s) => Ok(s),
None => Err(SVDErrorKind::MissingTag(self.clone(), n.to_string()).into()),
None => Err(SVDError::MissingTag(self.clone(), n.to_string()).into()),
}
}

/// Get a u32 value from a named child element
fn get_child_u32(&self, n: &str) -> Result<u32, SVDError> {
fn get_child_u32(&self, n: &str) -> Result<u32> {
let s = self.get_child_elem(n)?;
u32::parse(&s)
.context(SVDErrorKind::ParseError(self.clone()))
.map_err(|e| e.into())
u32::parse(&s).context(SVDError::ParseError(self.clone()))
}

/// Get a bool value from a named child element
fn get_child_bool(&self, n: &str) -> Result<bool, SVDError> {
fn get_child_bool(&self, n: &str) -> Result<bool> {
let s = self.get_child_elem(n)?;
BoolParse::parse(s)
}
Expand Down
101 changes: 20 additions & 81 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,63 +1,46 @@
//! SVD Errors.
//! This module defines error types and messages for SVD parsing and encoding

use core::fmt::{self, Display};
use failure::{Backtrace, Context, Fail};
use xmltree::{Element, ParseError};
pub use anyhow::{Context, Result};
use xmltree::Element;

#[derive(Debug)]
pub struct SVDError {
inner: Context<SVDErrorKind>,
}

// TODO: Expand and make more complex output possible.
// We can use the `Element` to output name (if available) and etc.
#[allow(clippy::large_enum_variant)]
#[derive(Clone, Debug, PartialEq, Eq, Fail)]
pub enum SVDErrorKind {
#[fail(display = "Unknown endianness `{}`", _0)]
#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
pub enum SVDError {
#[error("Unknown endianness `{0}`")]
UnknownEndian(String),
// TODO: Needs context
// TODO: Better name
#[fail(display = "Expected a <{}> tag, found none", _1)]
#[error("Expected a <{1}> tag, found none")]
MissingTag(Element, String),
#[fail(display = "Expected content in <{}> tag, found none", _1)]
#[error("Expected content in <{1}> tag, found none")]
EmptyTag(Element, String),
#[fail(display = "ParseError")]
#[error("ParseError")]
ParseError(Element),
#[fail(display = "NameMismatch")]
#[error("NameMismatch")]
NameMismatch(Element),
#[fail(display = "unknown access variant '{}' found", _1)]
#[error("unknown access variant '{1}' found")]
UnknownAccessType(Element, String),
#[fail(display = "Bit range invalid, {:?}", _1)]
#[error("Bit range invalid, {1:?}")]
InvalidBitRange(Element, InvalidBitRange),
#[fail(display = "Unknown write constraint")]
#[error("Unknown write constraint")]
UnknownWriteConstraint(Element),
#[fail(display = "Multiple wc found")]
#[error("Multiple wc found")]
MoreThanOneWriteConstraint(Element),
#[fail(display = "Unknown usage variant")]
#[error("Unknown usage variant")]
UnknownUsageVariant(Element),
#[fail(display = "Expected a <{}>, found ...", _1)]
#[error("Expected a <{1}>, found ...")]
NotExpectedTag(Element, String),
#[fail(
display = "Invalid RegisterCluster (expected register or cluster), found {}",
_1
)]
#[error("Invalid RegisterCluster (expected register or cluster), found {1}")]
InvalidRegisterCluster(Element, String),
#[fail(display = "Invalid modifiedWriteValues variant, found {}", _1)]
#[error("Invalid modifiedWriteValues variant, found {1}")]
InvalidModifiedWriteValues(Element, String),
#[fail(
display = "The content of the element could not be parsed to a boolean value {}: {}",
_1, _2
)]
#[error("The content of the element could not be parsed to a boolean value {1}: {2}")]
InvalidBooleanValue(Element, String, core::str::ParseBoolError),
#[fail(display = "encoding method not implemented for svd object {}", _0)]
#[error("encoding method not implemented for svd object {0}")]
EncodeNotImplemented(String),
#[fail(display = "Error parsing SVD XML")]
#[error("Error parsing SVD XML")]
FileParseError,
// FIXME: Should not be used, only for prototyping
#[fail(display = "{}", _0)]
Other(String),
}

// TODO: Consider making into an Error
Expand All @@ -67,47 +50,3 @@ pub enum InvalidBitRange {
ParseError,
MsbLsb,
}

impl Fail for SVDError {
fn cause(&self) -> Option<&dyn Fail> {
self.inner.cause()
}

fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}

impl Display for SVDError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Display::fmt(&self.inner, f)
}
}

impl SVDError {
pub fn kind(&self) -> SVDErrorKind {
self.inner.get_context().clone()
}
}

impl From<SVDErrorKind> for SVDError {
fn from(kind: SVDErrorKind) -> SVDError {
SVDError {
inner: Context::new(kind),
}
}
}

impl From<Context<SVDErrorKind>> for SVDError {
fn from(inner: Context<SVDErrorKind>) -> SVDError {
SVDError { inner }
}
}

impl From<ParseError> for SVDError {
fn from(e: ParseError) -> SVDError {
SVDError {
inner: e.context(SVDErrorKind::FileParseError),
}
}
}
11 changes: 7 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub mod svd;
pub use svd::*;
// Error defines SVD error types
pub mod error;
use error::SVDError;
use anyhow::Result;
// Parse defines parsing interfaces
pub mod parse;
use parse::Parse;
Expand All @@ -54,15 +54,15 @@ pub mod derive_from;
pub use derive_from::DeriveFrom;

/// Parses the contents of an SVD (XML) string
pub fn parse(xml: &str) -> Result<Device, SVDError> {
pub fn parse(xml: &str) -> Result<Device> {
let xml = trim_utf8_bom(xml);
let tree = Element::parse(xml.as_bytes())?;
Device::parse(&tree)
}

/// Encodes a device object to an SVD (XML) string
#[cfg(feature = "unproven")]
pub fn encode(d: &Device) -> Result<String, SVDError> {
pub fn encode(d: &Device) -> Result<String> {
let root = d.encode()?;
let mut wr = Vec::new();
root.write(&mut wr).unwrap();
Expand Down Expand Up @@ -98,7 +98,10 @@ pub(crate) fn new_element(name: &str, text: Option<String>) -> Element {
#[cfg(test)]
#[cfg(feature = "unproven")]
pub fn run_test<
T: Parse<Error = SVDError, Object = T> + Encode<Error = SVDError> + core::fmt::Debug + PartialEq,
T: Parse<Error = anyhow::Error, Object = T>
+ Encode<Error = anyhow::Error>
+ core::fmt::Debug
+ PartialEq,
>(
tests: &[(T, &str)],
) {
Expand Down
6 changes: 2 additions & 4 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

use xmltree::Element;

use crate::error::*;

/// Parse trait allows SVD objects to be parsed from XML elements.
pub trait Parse {
/// Object returned by parse method
Expand All @@ -18,9 +16,9 @@ pub trait Parse {
/// Parses an optional child element with the provided name and Parse function
/// Returns an none if the child doesn't exist, Ok(Some(e)) if parsing succeeds,
/// and Err() if parsing fails.
pub fn optional<'a, T>(n: &str, e: &'a Element) -> Result<Option<T::Object>, SVDError>
pub fn optional<'a, T>(n: &str, e: &'a Element) -> anyhow::Result<Option<T::Object>>
where
T: Parse<Error = SVDError>,
T: Parse<Error = anyhow::Error>,
{
let child = match e.get_child(n) {
Some(c) => c,
Expand Down
10 changes: 5 additions & 5 deletions src/svd/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ pub enum Access {

impl Parse for Access {
type Object = Access;
type Error = SVDError;
type Error = anyhow::Error;

fn parse(tree: &Element) -> Result<Access, SVDError> {
fn parse(tree: &Element) -> Result<Access> {
let text = tree.get_text()?;

match &text[..] {
Expand All @@ -31,16 +31,16 @@ impl Parse for Access {
"read-writeOnce" => Ok(Access::ReadWriteOnce),
"write-only" => Ok(Access::WriteOnly),
"writeOnce" => Ok(Access::WriteOnce),
_ => Err(SVDErrorKind::UnknownAccessType(tree.clone(), text).into()),
_ => Err(SVDError::UnknownAccessType(tree.clone(), text).into()),
}
}
}

#[cfg(feature = "unproven")]
impl Encode for Access {
type Error = SVDError;
type Error = anyhow::Error;

fn encode(&self) -> Result<Element, SVDError> {
fn encode(&self) -> Result<Element> {
let text = match *self {
Access::ReadOnly => String::from("read-only"),
Access::ReadWrite => String::from("read-write"),
Expand Down
10 changes: 5 additions & 5 deletions src/svd/addressblock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::types::Parse;

#[cfg(feature = "unproven")]
use crate::encode::Encode;
use crate::error::SVDError;
use crate::error::*;
#[cfg(feature = "unproven")]
use crate::new_element;

Expand All @@ -22,9 +22,9 @@ pub struct AddressBlock {

impl Parse for AddressBlock {
type Object = AddressBlock;
type Error = SVDError;
type Error = anyhow::Error;

fn parse(tree: &Element) -> Result<AddressBlock, SVDError> {
fn parse(tree: &Element) -> Result<AddressBlock> {
Ok(AddressBlock {
offset: tree.get_child_u32("offset")?,
size: tree.get_child_u32("size")?,
Expand All @@ -35,9 +35,9 @@ impl Parse for AddressBlock {

#[cfg(feature = "unproven")]
impl Encode for AddressBlock {
type Error = SVDError;
type Error = anyhow::Error;

fn encode(&self) -> Result<Element, SVDError> {
fn encode(&self) -> Result<Element> {
Ok(Element {
prefix: None,
namespace: None,
Expand Down
Loading