dfu_core/
memory_layout.rs1#[cfg(any(feature = "std", test))]
2use displaydoc::Display;
3#[cfg(any(feature = "std", test))]
4use std::prelude::v1::*;
5#[cfg(any(feature = "std", test))]
6use thiserror::Error;
7
8#[cfg(any(feature = "std", test))]
10#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
11#[derive(Debug, Display, Error)]
12pub enum Error {
13 InvalidPageFormat(String),
15 ParseErrorPageCount(String),
17 ParseErrorPageSize(String),
19 InvalidPrefix(String),
21}
22
23pub type MemoryPage = u32;
25
26#[allow(non_camel_case_types)]
28pub type mem = [MemoryPage];
29
30#[cfg(any(feature = "std", test))]
32#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
33pub struct MemoryLayout(Vec<MemoryPage>);
34
35#[cfg(any(feature = "std", test))]
36impl AsRef<mem> for MemoryLayout {
37 fn as_ref(&self) -> &mem {
38 self.0.as_slice()
39 }
40}
41
42#[cfg(any(feature = "std", test))]
43impl MemoryLayout {
44 pub fn new() -> Self {
46 Self(Vec::new())
47 }
48}
49
50#[cfg(any(feature = "std", test))]
51impl Default for MemoryLayout {
52 fn default() -> Self {
53 Self::new()
54 }
55}
56
57#[cfg(any(feature = "std", test))]
58impl From<Vec<MemoryPage>> for MemoryLayout {
59 fn from(vec: Vec<MemoryPage>) -> Self {
60 Self(vec)
61 }
62}
63
64#[cfg(any(feature = "std", test))]
65impl core::ops::Deref for MemoryLayout {
66 type Target = Vec<MemoryPage>;
67
68 fn deref(&self) -> &Self::Target {
69 &self.0
70 }
71}
72
73#[cfg(any(feature = "std", test))]
74impl core::ops::DerefMut for MemoryLayout {
75 fn deref_mut(&mut self) -> &mut Self::Target {
76 &mut self.0
77 }
78}
79
80#[cfg(any(feature = "std", test))]
81impl core::convert::TryFrom<&str> for MemoryLayout {
82 type Error = Error;
83
84 fn try_from(src: &str) -> Result<Self, Self::Error> {
85 use core::str::FromStr;
86
87 let mut pages = Vec::new();
88
89 for s in src.split(',') {
90 let (count, size) = s
91 .split_once('*')
92 .ok_or_else(|| Error::InvalidPageFormat(s.into()))?;
93 let (size, prefix) = size.split_at(
94 size.len()
95 .checked_sub(2)
96 .ok_or_else(|| Error::ParseErrorPageSize(size.into()))?,
97 );
98
99 let count =
100 u32::from_str(count).map_err(|_| Error::ParseErrorPageCount(count.into()))?;
101 let size = u32::from_str(size).map_err(|_| Error::ParseErrorPageSize(size.into()))?;
102 let prefix = match &prefix[..1] {
103 "K" => 1024,
104 "M" => 1024 * 1024,
105 " " => 1,
106 other => return Err(Error::InvalidPrefix(other.into())),
107 };
108
109 let size = size * prefix;
110 for _ in 0..count {
111 pages.push(size);
112 }
113 }
114
115 Ok(Self(pages))
116 }
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122 use core::convert::TryFrom;
123
124 #[test]
125 fn parsing() {
126 let s = "04*032Kg,01*128Kg,07*256Kg";
127 let m = MemoryLayout::try_from(s).unwrap();
128 assert_eq!(
129 m.as_slice(),
130 &[
131 32768, 32768, 32768, 32768, 131072, 262144, 262144, 262144, 262144, 262144, 262144,
132 262144
133 ]
134 );
135 }
136
137 #[test]
138 fn parsing_stm32_defuse_extensions() {
139 let s = "4*32Kg,1*128Kg";
140 let m = MemoryLayout::try_from(s).unwrap();
141 assert_eq!(m.as_slice(), &[32768, 32768, 32768, 32768, 131072]);
142 }
143}