use crate::Error;
use crate::packet::Padding;
pub const MIN_ID: u8 = 3;
pub const MAX_ID: u8 = 127;
const MAX_FRAMES: usize = 48;
const TOO_MANY_FRAMES: Error = Error::bad_arg("invalid argument: nb_frames is above 48");
const COUNTS_TOO_SHORT: Error = Error::bad_arg("invalid argument: nb_frame_exts is shorter than nb_frames");
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[non_exhaustive]
pub struct Extension<'a> {
pub id: u8,
pub frame: usize,
pub data: &'a [u8],
}
impl<'a> Extension<'a> {
pub const fn new(id: u8, frame: usize, data: &'a [u8]) -> Self {
Extension { id, frame, data }
}
}
fn skip_extension_payload(
data: &[u8],
pos: usize,
len: usize,
id_byte: u8,
trailing_short_len: usize,
) -> Option<(usize, usize, usize)> {
let id = id_byte >> 1;
let l = (id_byte & 1) as usize;
let (mut pos, mut len) = (pos, len);
let mut header_size = 0;
if (id == 0 && l == 1) || id == 2 {
} else if id > 0 && id < 32 {
if len < l {
return None;
}
pos += l;
len -= l;
} else if l == 0 {
if len < trailing_short_len {
return None;
}
pos += len - trailing_short_len;
len = trailing_short_len;
} else {
let mut bytes = 0usize;
loop {
if len < 1 {
return None;
}
let lacing = data[pos] as usize;
pos += 1;
bytes += lacing;
header_size += 1;
if len < lacing + 1 {
return None;
}
len -= lacing + 1;
if lacing != 255 {
break;
}
}
pos += bytes;
}
Some((pos, len, header_size))
}
fn skip_extension(data: &[u8], pos: usize, len: usize) -> Option<(usize, usize, usize)> {
if len == 0 {
return Some((pos, 0, 0));
}
let id_byte = data[pos];
let (pos, len, header_size) = skip_extension_payload(data, pos + 1, len - 1, id_byte, 0)?;
Some((pos, len, header_size + 1))
}
#[derive(Clone, Debug)]
pub struct ExtensionIterator<'a> {
data: &'a [u8],
curr: usize,
curr_len: usize,
failed: bool,
repeat_data: usize,
repeat_len: usize,
last_long: Option<usize>,
src: usize,
src_len: usize,
trailing_short_len: usize,
nb_frames: usize,
frame_max: usize,
curr_frame: usize,
repeat_frame: usize,
repeat_l: u8,
}
impl<'a> ExtensionIterator<'a> {
pub fn new(data: &'a [u8], nb_frames: usize) -> Self {
ExtensionIterator {
data,
curr: 0,
curr_len: data.len(),
failed: false,
repeat_data: 0,
repeat_len: 0,
last_long: None,
src: 0,
src_len: 0,
trailing_short_len: 0,
nb_frames,
frame_max: nb_frames,
curr_frame: 0,
repeat_frame: 0,
repeat_l: 0,
}
}
pub fn reset(&mut self) {
self.failed = false;
self.repeat_data = 0;
self.curr = 0;
self.last_long = None;
self.curr_len = self.data.len();
self.repeat_frame = 0;
self.curr_frame = 0;
self.trailing_short_len = 0;
}
pub fn set_frame_max(&mut self, frame_max: usize) {
self.frame_max = frame_max;
}
fn fail(&mut self) -> Error {
self.failed = true;
Error::INVALID_PACKET
}
fn next_repeat(&mut self) -> Result<Option<Extension<'a>>, Error> {
debug_assert!(self.repeat_frame > 0);
while self.repeat_frame < self.nb_frames {
while self.src_len > 0 {
let mut repeat_id_byte = self.data[self.src];
let Some((src, src_len, _)) = skip_extension(self.data, self.src, self.src_len) else {
return Err(self.fail());
};
self.src = src;
self.src_len = src_len;
if repeat_id_byte <= 3 {
continue;
}
if self.repeat_l == 0 && self.repeat_frame + 1 >= self.nb_frames && Some(self.src) == self.last_long {
repeat_id_byte &= !1;
}
let curr0 = self.curr;
let Some((curr, curr_len, header_size)) =
skip_extension_payload(self.data, self.curr, self.curr_len, repeat_id_byte, self.trailing_short_len)
else {
return Err(self.fail());
};
self.curr = curr;
self.curr_len = curr_len;
if self.repeat_frame >= self.frame_max {
continue;
}
return Ok(Some(Extension {
id: repeat_id_byte >> 1,
frame: self.repeat_frame,
data: &self.data[curr0 + header_size..self.curr],
}));
}
self.src = self.repeat_data;
self.src_len = self.repeat_len;
self.repeat_frame += 1;
}
self.repeat_data = self.curr;
self.last_long = None;
if self.repeat_l == 0 {
self.curr_frame += 1;
if self.curr_frame >= self.nb_frames {
self.curr_len = 0;
}
}
self.repeat_frame = 0;
Ok(None)
}
fn next_extension(&mut self) -> Result<Option<Extension<'a>>, Error> {
if self.repeat_frame > 0 {
if let Some(ext) = self.next_repeat()? {
return Ok(Some(ext));
}
}
if self.curr_frame >= self.frame_max {
return Ok(None);
}
while self.curr_len > 0 {
let curr0 = self.curr;
if self.data[curr0] == 0x01 {
let rest = &self.data[curr0..curr0 + self.curr_len];
let run = rest.iter().position(|&b| b != 0x01).unwrap_or(rest.len());
self.curr += run;
self.curr_len -= run;
continue;
}
let id = self.data[curr0] >> 1;
let l = self.data[curr0] & 1;
let Some((curr, curr_len, header_size)) = skip_extension(self.data, self.curr, self.curr_len) else {
return Err(self.fail());
};
self.curr = curr;
self.curr_len = curr_len;
if id == 1 {
if l == 0 {
self.curr_frame += 1;
} else {
let increment = self.data[curr0 + 1] as usize;
if increment == 0 {
continue;
}
self.curr_frame += increment;
}
if self.curr_frame >= self.nb_frames {
return Err(self.fail());
}
if self.curr_frame >= self.frame_max {
self.curr_len = 0;
}
self.repeat_data = self.curr;
self.last_long = None;
self.trailing_short_len = 0;
} else if id == 2 {
self.repeat_l = l;
self.repeat_frame = self.curr_frame + 1;
self.repeat_len = curr0 - self.repeat_data;
self.src = self.repeat_data;
self.src_len = self.repeat_len;
if let Some(ext) = self.next_repeat()? {
return Ok(Some(ext));
}
} else if id > 2 {
if id >= 32 {
self.last_long = Some(self.curr);
self.trailing_short_len = 0;
} else {
self.trailing_short_len += l as usize;
}
return Ok(Some(Extension {
id,
frame: self.curr_frame,
data: &self.data[curr0 + header_size..self.curr],
}));
}
}
Ok(None)
}
pub fn find_id(&mut self, id: u8) -> Result<Option<Extension<'a>>, Error> {
for ext in self.by_ref() {
let ext = ext?;
if ext.id == id {
return Ok(Some(ext));
}
}
Ok(None)
}
}
impl<'a> Iterator for ExtensionIterator<'a> {
type Item = Result<Extension<'a>, Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.failed {
return None;
}
if self.nb_frames > MAX_FRAMES {
self.failed = true;
return Some(Err(TOO_MANY_FRAMES));
}
self.next_extension().transpose()
}
}
pub fn count(data: &[u8], nb_frames: usize) -> Result<usize, Error> {
if nb_frames > MAX_FRAMES {
return Err(TOO_MANY_FRAMES);
}
Ok(ExtensionIterator::new(data, nb_frames).map_while(Result::ok).count())
}
pub(crate) fn count_checked(data: &[u8], nb_frames: usize) -> Result<usize, Error> {
let mut n = 0;
for ext in ExtensionIterator::new(data, nb_frames) {
ext?;
n += 1;
}
Ok(n)
}
pub fn count_ext(data: &[u8], nb_frame_exts: &mut [usize], nb_frames: usize) -> Result<usize, Error> {
if nb_frames > MAX_FRAMES {
return Err(TOO_MANY_FRAMES);
}
let counts = nb_frame_exts.get_mut(..nb_frames).ok_or(COUNTS_TOO_SHORT)?;
counts.fill(0);
let mut n = 0;
for ext in ExtensionIterator::new(data, nb_frames).map_while(Result::ok) {
counts[ext.frame] += 1;
n += 1;
}
Ok(n)
}
pub fn parse<'a>(data: &'a [u8], out: &mut [Extension<'a>], nb_frames: usize) -> Result<usize, Error> {
if nb_frames > MAX_FRAMES {
return Err(TOO_MANY_FRAMES);
}
let mut n = 0;
for ext in ExtensionIterator::new(data, nb_frames) {
let ext = ext?;
let slot = out.get_mut(n).ok_or(Error::BUFFER_TOO_SMALL)?;
*slot = ext;
n += 1;
}
Ok(n)
}
pub fn parse_ext<'a>(
data: &'a [u8],
out: &mut [Extension<'a>],
nb_frame_exts: &[usize],
nb_frames: usize,
) -> Result<usize, Error> {
if nb_frames > MAX_FRAMES {
return Err(TOO_MANY_FRAMES);
}
let counts = nb_frame_exts.get(..nb_frames).ok_or(COUNTS_TOO_SHORT)?;
let mut next = [0usize; MAX_FRAMES];
let mut total = 0usize;
for (start, &count) in next.iter_mut().zip(counts) {
*start = total;
total = total.saturating_add(count);
}
let mut n = 0;
for ext in ExtensionIterator::new(data, nb_frames) {
let ext = ext?;
let idx = next[ext.frame];
next[ext.frame] = idx.saturating_add(1);
let slot = out.get_mut(idx).ok_or(Error::BUFFER_TOO_SMALL)?;
*slot = ext;
n += 1;
}
Ok(n)
}
struct Out<'o> {
data: Option<&'o mut [u8]>,
len: usize,
}
impl Out<'_> {
fn put(&mut self, pos: usize, byte: u8) {
if let Some(d) = self.data.as_deref_mut() {
d[pos] = byte;
}
}
fn put_all(&mut self, pos: usize, bytes: &[u8]) {
if let Some(d) = self.data.as_deref_mut() {
d[pos..pos + bytes.len()].copy_from_slice(bytes);
}
}
}
fn write_extension_payload(out: &mut Out, pos: usize, ext: &Extension, last: bool) -> Result<usize, Error> {
let mut pos = pos;
let n = ext.data.len();
if ext.id < 32 {
if n > 1 {
return Err(Error::BAD_ARG);
}
if n > 0 {
if out.len - pos < n {
return Err(Error::BUFFER_TOO_SMALL);
}
out.put(pos, ext.data[0]);
pos += 1;
}
} else {
let length_bytes = if last { 0 } else { 1 + n / 255 };
if out.len - pos < length_bytes + n {
return Err(Error::BUFFER_TOO_SMALL);
}
if !last {
for _ in 0..n / 255 {
out.put(pos, 255);
pos += 1;
}
out.put(pos, (n % 255) as u8);
pos += 1;
}
out.put_all(pos, ext.data);
pos += n;
}
Ok(pos)
}
fn write_extension(out: &mut Out, pos: usize, ext: &Extension, last: bool) -> Result<usize, Error> {
if out.len - pos < 1 {
return Err(Error::BUFFER_TOO_SMALL);
}
let l = if ext.id < 32 { ext.data.len() as u8 } else { u8::from(!last) };
out.put(pos, (ext.id << 1).wrapping_add(l));
write_extension_payload(out, pos + 1, ext, last)
}
fn generate_impl(
mut out: Out,
extensions: &[Extension],
nb_frames: usize,
pad: bool,
) -> Result<usize, Error> {
if nb_frames > MAX_FRAMES {
return Err(TOO_MANY_FRAMES);
}
let n = extensions.len();
let len = out.len;
let mut frame_min_idx = [n; MAX_FRAMES];
let mut frame_max_idx = [0usize; MAX_FRAMES];
for (i, ext) in extensions.iter().enumerate() {
let f = ext.frame;
if f >= nb_frames || ext.id < MIN_ID || ext.id > MAX_ID {
return Err(Error::BAD_ARG);
}
frame_min_idx[f] = frame_min_idx[f].min(i);
frame_max_idx[f] = frame_max_idx[f].max(i + 1);
}
let mut frame_repeat_idx = frame_min_idx;
let mut curr_frame = 0usize;
let mut pos = 0usize;
let mut written = 0usize;
for f in 0..nb_frames {
let mut last_long_idx: Option<usize> = None;
let mut repeat_count = 0usize;
if f + 1 < nb_frames {
for i in frame_min_idx[f]..frame_max_idx[f] {
if extensions[i].frame != f {
continue;
}
let mut g = f + 1;
while g < nb_frames {
if frame_repeat_idx[g] >= frame_max_idx[g] {
break;
}
let other = &extensions[frame_repeat_idx[g]];
if other.id != extensions[i].id {
break;
}
if other.id < 32 && other.data.len() != extensions[i].data.len() {
break;
}
g += 1;
}
if g < nb_frames {
break;
}
if extensions[i].id >= 32 {
last_long_idx = Some(frame_repeat_idx[nb_frames - 1]);
}
for g in f + 1..nb_frames {
let mut j = frame_repeat_idx[g] + 1;
while j < frame_max_idx[g] && extensions[j].frame != g {
j += 1;
}
frame_repeat_idx[g] = j;
}
repeat_count += 1;
frame_repeat_idx[f] = i;
}
}
let mut i = frame_min_idx[f];
while i < frame_max_idx[f] {
if extensions[i].frame == f {
if f != curr_frame {
let diff = f - curr_frame;
if len - pos < 2 {
return Err(Error::BUFFER_TOO_SMALL);
}
if diff == 1 {
out.put(pos, 0x02);
pos += 1;
} else {
out.put(pos, 0x03);
out.put(pos + 1, diff as u8);
pos += 2;
}
curr_frame = f;
}
pos = write_extension(&mut out, pos, &extensions[i], written + 1 == n)?;
written += 1;
if repeat_count > 0 && frame_repeat_idx[f] == i {
let nb_repeated = repeat_count * (nb_frames - (f + 1));
let last = written + nb_repeated == n || (last_long_idx.is_none() && i + 1 >= frame_max_idx[f]);
if len - pos < 1 {
return Err(Error::BUFFER_TOO_SMALL);
}
out.put(pos, 0x04 + u8::from(!last));
pos += 1;
for g in f + 1..nb_frames {
let mut j = frame_min_idx[g];
while j < frame_repeat_idx[g] {
if extensions[j].frame == g {
pos = write_extension_payload(&mut out, pos, &extensions[j], last && Some(j) == last_long_idx)?;
written += 1;
}
j += 1;
}
frame_min_idx[g] = j;
}
if last {
curr_frame += 1;
}
}
}
i += 1;
}
}
debug_assert_eq!(written, n);
if pad && pos < len {
let padding = len - pos;
if let Some(d) = out.data.as_deref_mut() {
d.copy_within(0..pos, padding);
d[..padding].fill(0x01);
}
pos += padding;
}
Ok(pos)
}
pub fn generate(out: &mut [u8], extensions: &[Extension], nb_frames: usize, padding: Padding) -> Result<usize, Error> {
let len = out.len();
generate_impl(Out { data: Some(out), len }, extensions, nb_frames, padding.fills_buffer())
}
pub fn generated_len(max_len: usize, extensions: &[Extension], nb_frames: usize) -> Result<usize, Error> {
generate_impl(Out { data: None, len: max_len }, extensions, nb_frames, false)
}
const INLINE_EXTENSIONS: usize = 32;
pub(crate) struct ExtensionList<'a> {
inline: [Extension<'a>; INLINE_EXTENSIONS],
len: usize,
#[cfg(feature = "alloc")]
heap: alloc::vec::Vec<Extension<'a>>,
}
impl<'a> ExtensionList<'a> {
pub(crate) fn with_capacity(capacity: usize) -> Result<Self, Error> {
#[cfg(not(feature = "alloc"))]
if capacity > INLINE_EXTENSIONS {
return Err(Error::new(
crate::ErrorKind::AllocFail,
"more than 32 extensions need the alloc feature",
));
}
Ok(ExtensionList {
inline: [Extension::default(); INLINE_EXTENSIONS],
len: 0,
#[cfg(feature = "alloc")]
heap: if capacity > INLINE_EXTENSIONS { alloc::vec::Vec::with_capacity(capacity) } else { alloc::vec::Vec::new() },
})
}
pub(crate) fn push(&mut self, ext: Extension<'a>) {
#[cfg(feature = "alloc")]
if self.heap.capacity() > 0 {
self.heap.push(ext);
return;
}
self.inline[self.len] = ext;
self.len += 1;
}
pub(crate) fn as_slice(&self) -> &[Extension<'a>] {
#[cfg(feature = "alloc")]
if self.heap.capacity() > 0 {
return &self.heap;
}
&self.inline[..self.len]
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
use crate::ErrorKind;
type Plain = (u8, usize, Vec<u8>);
fn all(data: &[u8], nb_frames: usize) -> Result<Vec<Plain>, Error> {
ExtensionIterator::new(data, nb_frames).map(|e| e.map(|e| (e.id, e.frame, e.data.to_vec()))).collect()
}
#[test]
fn padding_and_short_and_long_extensions() {
let data = [0x01, 0x07, 0xAA, 0x41, 2, 1, 2, 0x42, 9, 9, 9];
let v = all(&data, 1).unwrap();
assert_eq!(v, [(3, 0, vec![0xAA]), (32, 0, vec![1, 2]), (33, 0, vec![9, 9, 9])]);
assert_eq!(count(&data, 1), Ok(3));
assert_eq!(all(&[0, 0, 0], 1).unwrap(), []);
assert_eq!(all(&[0x41, 5, 1], 1), Err(Error::INVALID_PACKET));
}
#[test]
fn separators_and_their_limits() {
let data = [0x06, 0x02, 0x08, 0x03, 2, 0x0A];
let v = all(&data, 4).unwrap();
assert_eq!(v, [(3, 0, vec![]), (4, 1, vec![]), (5, 3, vec![])]);
assert_eq!(all(&data, 3), Err(Error::INVALID_PACKET));
let mut it = ExtensionIterator::new(&data, 4);
it.set_frame_max(2);
assert_eq!(it.next().map(|e| e.unwrap().frame), Some(0));
assert_eq!(it.next().map(|e| e.unwrap().frame), Some(1));
assert_eq!(it.next(), None);
}
#[test]
fn the_iterator_ends_after_an_error_until_reset() {
let data = [0x06, 0x02, 0x08];
let mut it = ExtensionIterator::new(&data, 1);
assert_eq!(it.next(), Some(Ok(Extension::new(3, 0, &[]))));
assert_eq!(it.next().map(|e| e.map_err(|e| e.kind())), Some(Err(ErrorKind::InvalidPacket)));
assert_eq!(it.next(), None);
assert_eq!(it.next(), None);
it.reset();
assert_eq!(it.next(), Some(Ok(Extension::new(3, 0, &[]))));
it.reset();
assert_eq!(it.find_id(4).map_err(|e| e.kind()), Err(ErrorKind::InvalidPacket));
assert_eq!(it.find_id(4), Ok(None));
let mut it = ExtensionIterator::new(&data, 2);
assert_eq!(it.find_id(4), Ok(Some(Extension::new(4, 1, &[]))));
assert_eq!(it.next(), None);
let ids: Result<Vec<u8>, Error> = ExtensionIterator::new(&data, 2).map(|e| e.map(|e| e.id)).collect();
assert_eq!(ids, Ok(vec![3, 4]));
assert_eq!(ExtensionIterator::new(&data, 2).find(|e| e.as_ref().is_ok_and(|e| e.frame == 1)), Some(Ok(Extension::new(4, 1, &[]))));
}
#[test]
fn more_than_48_frames_is_an_error_not_a_panic() {
let data = [0x07, 0xAA];
let mut it = ExtensionIterator::new(&data, 49);
assert_eq!(it.next().map(|e| e.map_err(|e| e.kind())), Some(Err(ErrorKind::BadArg)));
assert_eq!(it.next(), None);
assert_eq!(ExtensionIterator::new(&data, usize::MAX).find_id(3).map_err(|e| e.kind()), Err(ErrorKind::BadArg));
assert_eq!(ExtensionIterator::new(&data, 48).next(), Some(Ok(Extension::new(3, 0, &[0xAA]))));
assert_eq!(count(&data, 48), Ok(1));
let kind = |r: Result<usize, Error>| r.map_err(|e| e.kind());
assert_eq!(kind(count(&data, 49)), Err(ErrorKind::BadArg));
let mut counts = [7usize; 64];
assert_eq!(kind(count_ext(&data, &mut counts, 49)), Err(ErrorKind::BadArg));
assert_eq!(counts, [7; 64], "counts change on an error");
let mut out = [Extension::default(); 4];
assert_eq!(kind(parse(&data, &mut out, 49)), Err(ErrorKind::BadArg));
assert_eq!(kind(parse_ext(&data, &mut out, &counts, 49)), Err(ErrorKind::BadArg));
assert_eq!(kind(generate(&mut [0u8; 8], &[], 49, Padding::Shortest)), Err(ErrorKind::BadArg));
assert_eq!(kind(generated_len(8, &[], 49)), Err(ErrorKind::BadArg));
}
#[test]
fn too_few_frame_counts_is_an_error_not_a_panic() {
let data = [0x06, 0x02, 0x08];
let mut counts = [9usize; 1];
assert_eq!(count_ext(&data, &mut counts, 2).map_err(|e| e.kind()), Err(ErrorKind::BadArg));
assert_eq!(counts, [9], "counts change on an error");
let mut out = [Extension::default(); 4];
assert_eq!(parse_ext(&data, &mut out, &[1], 2).map_err(|e| e.kind()), Err(ErrorKind::BadArg));
assert_eq!(parse_ext(&data, &mut out, &[], 1).map_err(|e| e.kind()), Err(ErrorKind::BadArg));
let mut counts = [9usize; 3];
assert_eq!(count_ext(&data, &mut counts, 2), Ok(2));
assert_eq!(counts, [1, 1, 9]);
assert_eq!(parse_ext(&data, &mut out, &counts, 2), Ok(2));
assert_eq!(out[..2], [Extension::new(3, 0, &[]), Extension::new(4, 1, &[])]);
for bad in [[usize::MAX, usize::MAX], [usize::MAX, 0], [0, 0], [0, usize::MAX], [3, 3]] {
let r = parse_ext(&data, &mut out, &bad, 2);
assert!(matches!(r.map_err(|e| e.kind()), Ok(2) | Err(ErrorKind::BufferTooSmall)), "{bad:?}: {r:?}");
}
}
#[test]
fn extension_new_sets_the_fields() {
let payload = [1u8, 2];
const EMPTY: Extension<'static> = Extension::new(5, 2, &[]);
assert_eq!((EMPTY.id, EMPTY.frame, EMPTY.data), (5, 2, &[][..]));
let ext = Extension::new(40, 1, &payload);
assert_eq!((ext.id, ext.frame, ext.data), (40, 1, &payload[..]));
assert_eq!(ext, Extension { id: 40, frame: 1, data: &payload });
}
#[test]
fn generate_uses_repeats_and_parses_back() {
let payload = [1u8, 2, 3];
let mut exts = Vec::new();
for f in 0..4 {
exts.push(Extension::new(3, f, &[]));
exts.push(Extension::new(40, f, &payload));
}
let mut buf = [0u8; 64];
let n = generate(&mut buf, &exts, 4, Padding::Shortest).unwrap();
assert_eq!(generated_len(64, &exts, 4), Ok(n));
assert_eq!(n, 1 + 1 + 1 + 3 + 1 + 4 + 4 + 3);
let mut out = [Extension::default(); 8];
let mut counts = [0usize; 4];
assert_eq!(count_ext(&buf[..n], &mut counts, 4), Ok(8));
assert_eq!(counts, [2, 2, 2, 2]);
assert_eq!(parse_ext(&buf[..n], &mut out, &counts, 4), Ok(8));
assert_eq!(&out[..], &exts[..]);
let n2 = generate(&mut buf, &exts, 4, Padding::FillBuffer).unwrap();
assert_eq!(n2, 64);
assert_eq!(buf[0], 0x01);
assert_eq!(count(&buf, 4), Ok(8));
let bad = [Extension::new(2, 0, &[])];
assert_eq!(generate(&mut buf, &bad, 1, Padding::Shortest), Err(Error::BAD_ARG));
let bad = [Extension::new(3, 1, &[])];
assert_eq!(generate(&mut buf, &bad, 1, Padding::Shortest), Err(Error::BAD_ARG));
let bad = [Extension::new(3, 0, &[1, 2])];
assert_eq!(generate(&mut buf, &bad, 1, Padding::Shortest), Err(Error::BAD_ARG));
assert_eq!(generate(&mut buf[..5], &exts, 4, Padding::Shortest), Err(Error::BUFFER_TOO_SMALL));
}
}