1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
use core::ops::Deref;

use xmltree::Element;

use crate::types::Parse;

use crate::elementext::ElementExt;

use crate::encode::Encode;
use crate::error::*;
use crate::svd::{dimelement::DimElement, registerinfo::RegisterInfo};
use anyhow::Result;

#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum Register {
    Single(RegisterInfo),
    Array(RegisterInfo, DimElement),
}

impl Deref for Register {
    type Target = RegisterInfo;

    fn deref(&self) -> &RegisterInfo {
        match self {
            Register::Single(info) => info,
            Register::Array(info, _) => info,
        }
    }
}

impl Parse for Register {
    type Object = Self;
    type Error = anyhow::Error;

    fn parse(tree: &Element) -> Result<Self> {
        assert_eq!(tree.name, "register");

        let info = RegisterInfo::parse(tree)?;

        if tree.get_child("dimIncrement").is_some() {
            let array_info = DimElement::parse(tree)?;
            check_has_placeholder(&info.name, "register")?;
            if let Some(indices) = &array_info.dim_index {
                assert_eq!(array_info.dim as usize, indices.len())
            }
            Ok(Register::Array(info, array_info))
        } else {
            Ok(Register::Single(info))
        }
    }
}

impl Encode for Register {
    type Error = anyhow::Error;

    fn encode(&self) -> Result<Element> {
        match self {
            Register::Single(info) => info.encode(),
            Register::Array(info, array_info) => {
                // TODO: is this correct? probably not, need tests
                let mut base = info.encode()?;
                base.merge(&array_info.encode()?);
                Ok(base)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::dimelement::DimElementBuilder;
    use crate::registerinfo::RegisterInfoBuilder;

    use crate::run_test;
    #[test]
    fn decode_encode() {
        let tests = vec![(
            Register::Array(
                RegisterInfoBuilder::default()
                    .name("MODE%s".to_string())
                    .address_offset(8)
                    .build()
                    .unwrap(),
                DimElementBuilder::default()
                    .dim(2)
                    .dim_increment(4)
                    .dim_index(Some(vec!["10".to_string(), "20".to_string()]))
                    .build()
                    .unwrap(),
            ),
            "
            <register>
              <name>MODE%s</name>
              <addressOffset>0x8</addressOffset>
              <dim>2</dim>
              <dimIncrement>4</dimIncrement>
              <dimIndex>10,20</dimIndex>
            </register>
            ",
        )];
        run_test::<Register>(&tests[..]);
    }
}