use core::fmt::Write;
const KEY_CAP: usize = 24;
#[derive(Debug)]
pub(crate) struct KeyBuf {
buf: [u8; KEY_CAP],
len: usize,
}
impl KeyBuf {
pub(crate) fn new() -> KeyBuf {
KeyBuf {
buf: [0; KEY_CAP],
len: 0,
}
}
pub(crate) fn as_str(&self) -> &str {
std::str::from_utf8(&self.buf[..self.len]).expect("keyword bytes are ASCII")
}
}
impl Write for KeyBuf {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let end = self.len + s.len();
assert!(
end <= KEY_CAP,
"formatted FITS keyword exceeds {KEY_CAP} bytes"
);
self.buf[self.len..end].copy_from_slice(s.as_bytes());
self.len = end;
Ok(())
}
}
macro_rules! key {
($($arg:tt)*) => {{
let mut k = $crate::keyword::KeyBuf::new();
core::fmt::Write::write_fmt(&mut k, format_args!($($arg)*))
.expect("KeyBuf keyword write is infallible");
k
}};
}
pub(crate) use key;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn formats_indexed_keywords_without_allocating() {
let (i, j, m) = (1usize, 2usize, 15usize);
let a = "";
assert_eq!(key!("NAXIS{i}").as_str(), "NAXIS1");
assert_eq!(key!("PV{}_{m}{a}", j).as_str(), "PV2_15");
let a = "A";
assert_eq!(key!("CD{}_{}{a}", i, j).as_str(), "CD1_2A");
assert_eq!(key!("ZNAXIS{i}").as_str(), "ZNAXIS1");
}
#[test]
#[should_panic(expected = "exceeds")]
fn overlong_keyword_panics() {
let _ = key!("{}", "X".repeat(KEY_CAP + 1)).as_str();
}
}