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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
// We don't need anything from std, and on AVR there is no std anyway.
#![no_std]
//
// We need inline assembly for the `lpm` instruction.
// As of now (mid 2022), inline assembly for AVR is still unstable.
#![feature(asm_experimental_arch)]
//
// We to access the length of a slice pointer (for unsized `ProgMem`s)
#![feature(slice_ptr_len)]
//
// Allow to implement `CoerceUnsized` on `ProgMem`
#![cfg_attr(feature = "unsize", feature(coerce_unsized))]
//
// Needed for implementing `CoerceUnsized` on `ProgMem`
#![cfg_attr(feature = "unsize", feature(unsize))]
//
// Allows to document required crate features on items
#![cfg_attr(doc, feature(doc_auto_cfg))]
//
// Allow `unsafe` in `unsafe fn`s, and make `unsafe` blocks everywhere a
// necessity.
#![forbid(unsafe_op_in_unsafe_fn)]

//!
//! Progmem utilities for the AVR architectures.
//!
//! This crate provides unsafe utilities for working with data stored in
//! the program memory of an AVR micro-controller. Additionally, it defines a
//! 'best-effort' safe wrapper struct [`ProgMem`](crate::wrapper::ProgMem)
//! to simplify working with it,
//! as well as a [`PmString`](crate::string::PmString) wrapper for string
//! handling.
//!
//! This crate is implemented only in Rust and some short assembly, it does NOT
//! depend on the [`avr-libc`] or any other C-library. However, due to the use
//! of inline assembly, this crate may only be compiled using a **nightly Rust**
//! compiler (as of mid 2022, inline assembly for AVR is still 'experimental').
//!
//! ## MSRV
//!
//! This crate works with a Rust `nightly-2022-05-10` compiler.
//! All versions `0.3.x` will adhere to work with `nightly-2022-05-10`.
//! Other Rust compiler version (particularly newer ones) might also work,
//! but due to the use of experimental compiler features it is possible that
//! some future Rust compiler version will fail to work.
//!
//! Future versions such as `0.4.x` might required a newer Rust compiler
//! version.
//!
//!
//! # AVR Memory
//!
//! This crate is specifically for [AVR-base micro-controllers][avr] such as
//! the Arduino Uno (and some other Arduino boards, but not all), which have a
//! modified Harvard architecture which implies the strict separation of program
//! code and data while having special instructions to read and write to
//! program memory.
//!
//! While, of course, all ordinary data is stored in the data domain where it is
//! perfectly usable, the harsh constraints of most AVR processors make it very
//! appealing to use the program memory (also referred to as _progmem_) for
//! storing constant values. However, due to the Harvard design, those values
//! are not usable with normal instructions (i.e. those emitted from normal
//! Rust code). Instead, special instructions are required to load data from
//! the program code domain, such as the `lpm` (load \[from\] program memory)
//! instruction. And because there is no way to emit it from Rust code, this
//! crate uses inline assembly to emit that instruction.
//!
//! However, since a pointer into program code cannot be differentiated from a
//! normal data pointer, it is entirely up to the programmer to ensure that
//! these different 'pointer-types' are not accidentally mixed. In other words,
//! this is `unsafe` in the context of Rust.
//!
//!
//! # Loading Data from Program Memory
//!
//! The first part of this crate simply provides a few functions (e.g.
//! [`read_byte`](crate::raw::read_byte)) to load constant data (i.e. a Rust `static` that is
//! immutable) from the program memory into the data domain, so that
//! sub-sequentially it is normal usable data, i.e. as owned data on the stack.
//!
//! Because, as aforementioned, a simple `*const u8` in Rust does not specify
//! whether is lives in the program code domain or the data domain, all
//! functions which simply load a given pointer from the program memory are
//! inherently `unsafe`.
//!
//! Notice that using references (e.g. `&u8`) to the program code domain should
//! generally be avoided because references in Rust should be dereferencable,
//! which the program code domain is not.
//!
//! Additionally references can be easily dereferenced by safe code,
//! which would be **undefined behavior** if that reference points into the
//! program memory.
//! Therefore, a Rust reference to a `static` that is stored in program memory
//! must be considered hazardous (if not **UB**),
//! and it is recommended to only use raw pointers to those `static`s,
//! e.g. obtained via the [`addr_of!`](core::ptr::addr_of) macro,
//! which directly creates raw pointers without needing a reference.
//!
//! ## Example
//!
//! ```
//! use avr_progmem::raw::read_byte;
//! use core::ptr::addr_of;
//!
//! // This `static` must never be directly dereferenced/accessed!
//! // So a `let data: u8 = P_BYTE;` ⚠️ is **undefined behavior**!!!
//! /// Static byte stored in progmem!
//! #[link_section = ".progmem.data"]
//! static P_BYTE: u8 = b'A';
//!
//! // Load the byte from progmem
//! // Here, it is sound, because due to the link_section it is indeed in the
//! // program code memory.
//! let data: u8 = unsafe { read_byte(addr_of!(P_BYTE)) };
//! assert_eq!(b'A', data);
//! ```
//!
//!
//! # The best-effort Wrapper
//!
//! Since working with progmem data is inherently unsafe and rather
//! difficult to do correctly, this crate introduces the best-effort 'safe'
//! wrapper [`ProgMem`](crate::wrapper::ProgMem),
//! that is supposed to only wrap data in progmem, thus
//! offering only functions to load its content using the progmem loading
//! function introduced above.
//! Using these functions is sound, if that the wrapper data is really stored
//! in the program memory. Therefore, to enforce this invariant,
//! the constructor of `ProgMem` is `unsafe`.
//!
//! Additionally, since proper Rust references (unlike pointers) come with a lot
//! special requirements, it should be considered hazardous to have a reference
//! to data stored in program memory.
//! Instead, only raw pointers to this kind of data should be kept,
//! created e.g. via the [`addr_of!`](core::ptr::addr_of) macro.
//! Consequently, the `ProgMem` just wrap a pointer to data in progmem,
//! which in turn must be stored in a `static` marked with
//! `#[link_section = ".progmem.data"]`.
//! However, since, safe Rust can always create a "normal" Rust reference to any
//! (accessible) `static`, it must be considered hazardous if not just unsound,
//! to expose such a `static` to safe Rust code.
//!
//! To also make this easier (and less hazardous), this crate provides the
//! [`progmem!`] macro, which will create a hidden `static` in program memory
//! initialized with the data you give it,
//! wrap it's pointer in the `ProgMem` struct,
//! and put that wrapper into yet another (normal RAM) static, so you can
//! access it.
//! This will ensure that the `static` that is stored in program memory can not
//! be referenced by safe Rust code (because it is not accessible),
//! while the accessible `ProgMem` wrapper allows access to the underling data
//! by loading it correctly from program memory.
//!
//! ## Example
//!
//! ```
//! use avr_progmem::progmem;
//!
//! // It will be wrapped in the ProgMem struct and expand to:
//! // ```
//! // static P_BYTE: ProgMem<u8> = {
//! //     #[link_section = ".progmem.data"]
//! //     static INNER_HIDDEN: u8 = 42;
//! //     unsafe { ProgMem::new(addr_of!(INNER_HIDDEN)) }
//! // };
//! // ```
//! // Thus it is impossible for safe Rust to directly access the progmem data!
//! progmem! {
//!     /// Static byte stored in progmem!
//!     static progmem P_BYTE: u8 = 42;
//! }
//!
//! // Load the byte from progmem
//! // This is sound, because the `ProgMem` always uses the special operation to
//! // load the data from program memory.
//! let data: u8 = P_BYTE.load();
//! assert_eq!(42, data);
//! ```
//!
//!
//! # Strings
//!
//! Using strings such as `&str` with [`ProgMem`](crate::wrapper::ProgMem)
//! is rather difficult, and
//! surprisingly hard if Unicode support is needed
//! (see [issue #3](https://github.com/Cryptjar/avr-progmem-rs/issues/3)).
//! Thus, to make working with string convenient the
//! [`PmString`](string::PmString) struct is provided on top of
//! [`ProgMem`](crate::wrapper::ProgMem).
//!
//! [`PmString`](string::PmString) stores any given `&str` as statically sized
//! UTF-8 byte array (with full Unicode support).
//! To make its content usable, it provides a `Display` & `uDisplay`
//! implementation, a lazy [`chars`](string::PmString::chars) iterator,
//! and [`load`](string::PmString::load) function similar to
//! [`ProgMem`](crate::wrapper::ProgMem)'s
//! `load`,
//! that yields a [`LoadedString`](string::LoadedString),
//! which in turn defers to `&str`.
//!
//! For more details see the [string](crate::string) module.
//!
//! ## Example
//!
//! ```rust
//! use avr_progmem::progmem;
//!
//! progmem! {
//!     // A simple Unicode string in progmem.
//!     static progmem string TEXT = "Hello 大賢者";
//! }
//!
//! // You can load it and use that as `&str`
//! let buffer = TEXT.load();
//! assert_eq!("Hello 大賢者", &*buffer);
//!
//! // Or you use directly the `Display` impl
//! assert_eq!("Hello 大賢者", format!("{}", TEXT));
//! ```
//!
//! Additionally, two special macros are provided similar to the `F` macro
//! of the Arduino IDE, that allows to "mark" a string as to be stored in
//! progmem while being returned at this place as a loaded `&str`.
//!
//! ```rust
//! // Or you skip the static and use in-line progmem strings:
//! use avr_progmem::progmem_str as F;
//! use avr_progmem::progmem_display as D;
//!
//! // Either as `&str`
//! assert_eq!("Foo 大賢者", F!("Foo 大賢者"));
//!
//! // Or as some `impl Display + uDisplay`
//! assert_eq!("Bar 大賢者", format!("{}", D!("Bar 大賢者")));
//! ```
//!
//! If you enabled the `ufmt` crate feature (its a default feature),
//! you can also use `uDisplay` in addition to `Display`.
//!
//! ```rust
//! # #[cfg(feature = "ufmt")] // requires the `ufmt` crate feature
//! # {
//! #
//! use avr_progmem::progmem;
//! use avr_progmem::progmem_str as F;
//! use avr_progmem::progmem_display as D;
//!
//! fn foo<W: ufmt::uWrite>(writer: &mut W) {
//!     progmem! {
//!         // A simple Unicode string in progmem.
//!         static progmem string TEXT = "Hello 大賢者";
//!     }
//!
//!     // You can use the `uDisplay` impl
//!     ufmt::uwriteln!(writer, "{}", TEXT);
//!
//!     // Or use the in-line `&str`
//!     writer.write_str(F!("Foo 大賢者\n"));
//!
//!     // Or the in-line `impl uDisplay`
//!     ufmt::uwriteln!(writer, "{}", D!("Bar 大賢者"));
//! }
//! # struct MyWriter(String);
//! # impl ufmt::uWrite for MyWriter {
//! #     type Error = ();
//! #     fn write_str(&mut self, s: &str) -> Result<(),()> {
//! #         self.0.push_str(s);
//! #         Ok(())
//! #     }
//! # }
//! //
//! # let mut writer = MyWriter(String::new());
//! # foo(&mut writer);
//! # assert_eq!("Hello 大賢者\nFoo 大賢者\nBar 大賢者\n", writer.0);
//! # }
//! ```
//!
//!
//! # Other Architectures
//!
//! As mentioned before, this crate is specifically designed to be use with
//! AVR-base micro-controllers. But since most of us don't write their programs
//! on an AVR system but e.g. on x86 systems, and might want to test them
//! there (well as far as it is possible), this crate also has a fallback
//! implementation for all other architectures that are not AVR, falling back
//! to a simple Rust `static` in the default data segment. And all the data
//! loading functions will just dereference the pointed-to data, assuming that
//! they just live in the default location.
//!
//! This fallback is perfectly safe on x86 and friend, and should also be fine
//! on all further architectures, otherwise normal Rust `static`s would be
//! broken. However, it is an important point to know when for instance writing
//! a library that is not limited to AVR.
//!
//!
//! # Implementation Limitations
//!
//! Aside from what has been already been covered, the current implementation
//! has two further limitations.
//!
//! First, since this crate uses an inline assembly loop on a 8-bit
//! architecture, the loop counter only allows values up to 255. This means
//! that not more that 255 bytes can be loaded at once with any of the methods
//! of this crate. However, this only applies to a single continuous load
//! operation, so for instance `ProgMem<[u8;1024]>::load()` will panic, but
//! accessing such a big type in smaller chunks e.g.
//! `ProgMem<[u8;1024]>::load_sub_array::<[u8;128]>(512)` is perfectly fine
//! because the to be loaded type `[u8;128]` is only 128 bytes in size.
//! Notice that the same limitation holds for `PmString<N>::load()`
//! (i.e. you can only use it if `N <= 255` holds.
//! On the other hand, there is no such limitation on `PmString<N>::chars()`
//! and `PmString`'s `Display`/`uDisplay` implementation,
//! because those, just load each `char` individually
//! (i.e. no more that 4 bytes at a time).
//!
//! Second, since this crate only uses the `lpm` instruction, which is limited
//! by a 16-bit pointer, this crate may only be used with data stored in the
//! lower 64 kiB of program memory. Since this property has not be tested it is
//! unclear whether it will cause a panic or right-up undefined behavior, so be
//! very wary when working with AVR chips that have more then 64 kiB of program
//! memory.
//!
//! [`progmem!`]: https://docs.rs/avr-progmem/latest/avr_progmem/macro.progmem.html
//! [`avr-libc`]: https://crates.io/crates/avr-libc
//! [avr]: https://en.wikipedia.org/wiki/AVR_microcontrollers
//!



pub mod raw;
pub mod string;
pub mod wrapper;