#[doc = crate::_tags!(code mem)]
#[doc = crate::_doc_meta!{location("code/util")}]
#[macro_export]
#[cfg_attr(cargo_primary_package, doc(hidden))]
macro_rules! write_at· {
($buf:ident, += $offset:expr, $($elem:tt)*) => {{
#[allow(unused_mut, unused_assignments)]
{
let mut __offset = $offset;
$crate::write_at!(% $buf, __offset, $($elem)*);
$offset = __offset;
__offset
}
}};
($buf:ident, $offset:expr, $($elem:tt)*) => {{
#[allow(unused_mut, unused_assignments)]
{
let mut __offset = $offset;
$crate::write_at!(% $buf, __offset, $($elem)*);
__offset
}
}};
($buf:expr, += $offset:expr, $($elem:tt)*) => {{
#[allow(unused_mut, unused_assignments)]
{
let __buf = &mut $buf;
let mut __offset = $offset;
$crate::write_at!(% __buf, __offset, $($elem)*);
$offset = __offset;
__offset
}
}};
($buf:expr, $offset:expr, $($elem:tt)*) => {{
#[allow(unused_mut, unused_assignments)]
{
let __buf = &mut $buf;
let mut __offset = $offset;
$crate::write_at!(% __buf, __offset, $($elem)*);
__offset
}
}};
(% $buf:ident, $off:ident, @0 $seq:expr $(, $($t:tt)*)? ) => {{
$( $crate::write_at!(% $buf, $off, $($t)*); )?
}};
(% $buf:ident, $off:ident, @1 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 1 $($t)*); };
(% $buf:ident, $off:ident, @2 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 2 $($t)*); };
(% $buf:ident, $off:ident, @3 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 3 $($t)*); };
(% $buf:ident, $off:ident, @4 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 4 $($t)*); };
(% $buf:ident, $off:ident, @5 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 5 $($t)*); };
(% $buf:ident, $off:ident, @6 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 6 $($t)*); };
(% $buf:ident, $off:ident, @7 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 7 $($t)*); };
(% $buf:ident, $off:ident, @8 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 8 $($t)*); };
(% $buf:ident, $off:ident, @16 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 16 $($t)*); };
(% $buf:ident, $off:ident, @32 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 32 $($t)*); };
(% $buf:ident, $off:ident, @64 $($t:tt)*) => { $crate::write_at!(%unr $buf, $off, 64 $($t)*); };
(% unr $buf:ident, $off:ident, $n:tt $seq:expr $(, $($rest:tt)*)? ) => {{
let __seq = &$seq;
$crate::punroll![$n |i| { $buf[$off] = __seq[i]; $off += 1; }];
$( $crate::write_at!(% $buf, $off, $($rest)*); )?
}};
(% $buf:ident, $off:ident, @$seq:expr, $($rest:tt)*) => {{
let __seq = &$seq;
$crate::whilst! { i in 0..__seq.len(); { $buf[$off] = __seq[i]; $off += 1; }}
$crate::write_at!(% $buf, $off, $($rest)*);
}};
(% $buf:ident, $off:ident, @$seq:expr) => {{
let __seq = &$seq;
$crate::whilst! { i in 0..__seq.len(); { $buf[$off] = __seq[i]; $off += 1; }}
}};
(% $buf:ident, $off:ident, #$ch:expr, $($rest:tt)*) => {{
$crate::write_at!(%utf8_char $buf, $off, $ch);
$crate::write_at!(% $buf, $off, $($rest)*);
}};
(% $buf:ident, $off:ident, #$ch:expr) => {{
$crate::write_at!(%utf8_char $buf, $off, $ch);
}};
(% utf8_char $buf:ident, $off:ident, $ch:expr) => {{
$off += $crate::__unicode_scalar_write_utf8_at![$buf, $off, $ch];
}};
(% $buf:ident, $off:ident, $elem:expr, $($rest:tt)*) => {{
$buf[$off] = $elem;
$off += 1;
$crate::write_at!(% $buf, $off, $($rest)*);
}};
(% $buf:ident, $off:ident, $elem:expr) => {{
$buf[$off] = $elem;
$off += 1;
}};
(% $buf:ident, $off:ident $(,)?) => {};
}
pub use write_at· as write_at;
#[cfg(any(doctest, test))]
mod tests {
use super::write_at;
use crate::{Slice, Str};
#[test]
fn write_at() {
let mut buffer = [0u8; 20];
let mut offset = 0;
write_at!(buffer, +=offset, b'\x1b', b'P', b'q', b'"');
write_at!(buffer, +=offset, b'h', b'e', b'l', b'l', b'o');
write_at!(buffer, +=offset, b' ', b'w', b'o', b'r', b'l', b'd');
assert_eq![offset, 15];
assert_eq![&buffer[0..offset], b"\x1bPq\"hello world"];
}
#[test]
const fn const_write_at() {
let mut buffer = [0u8; 20];
let start = 3;
let mut offset = start;
write_at!(buffer, +=offset, b'\x1b', b'P', b'q', b'"');
write_at!(buffer, +=offset, b'h', b'e', b'l', b'l', b'o');
write_at!(buffer, +=offset, b' ', b'w', b'o', b'r', b'l', b'd');
let result = Slice::range(&buffer, 3, offset);
assert![offset == start + 15];
assert![Slice::<u8>::eq(result, b"\x1bPq\"hello world")];
}
#[test]
fn sequence_spread() {
let bytes = [6, 7, 8];
let mut buffer = [0u8; 10];
let mut offset = 0;
write_at!(buffer, +=offset, 1, 2, 3, 4, 5, @bytes, 9);
assert_eq![&buffer[0..offset], &[1, 2, 3, 4, 5, 6, 7, 8, 9]];
}
#[test]
#[should_panic(expected = "index out of bounds: the len is 4 but the index is 4")]
fn buffer_overflow() {
let mut buffer = [0u8; 4];
let mut offset = 0;
write_at!(buffer, +=offset, 1, 2, 3, 4, 5);
}
#[test]
fn unicode() {
let mut buf = [0u8; 12];
let mut offset = 0;
write_at![buf, +=offset, 0xC2, 0xB5]; write_at!(buf, +=offset, @"µ".as_bytes()); write_at!(buf, +=offset, #'µ'); assert_eq![Str::from_utf8(Slice::range_to(&buf, offset)), Ok("µµµ")];
}
#[test]
fn fixed_unrolled_sequence_spread() {
let id = *b"RIFF";
let mut dst = [0u8; 8];
let end = write_at!(dst, 0, @4 id);
assert_eq![end, 4];
assert_eq![&dst[..4], b"RIFF"];
}
#[test]
fn fixed_unrolled_sequence_spread_mut_offset() {
let id = *b"fmt ";
let mut dst = [0u8; 8];
let mut pos = 2;
let end = write_at!(dst, +=pos, @4 id);
assert_eq![end, 6];
assert_eq![pos, 6];
assert_eq![&dst[2..6], b"fmt "];
}
#[allow(dead_code)]
fn unsupported_fixed_arity() {}
}