#[cfg(creusot)]
use creusot_std::prelude::*;
#[cfg(creusot)]
use creusot_std::prelude::{Clone, PartialEq};
pub fn read_push_data_len(
data: &mut core::slice::Iter<'_, u8>,
size: PushDataLenLen,
) -> Result<u32, EarlyEndOfScriptError> {
let size = size.to_usize();
if data.len() < size {
return Err(EarlyEndOfScriptError);
}
let mut ret = 0;
let mut i = 0u32;
#[cfg_attr(creusot, invariant(i@ == produced.len()))]
#[cfg_attr(creusot, variant(size@ - produced.len()))]
#[allow(clippy::explicit_counter_loop)]
for item in data.take(size) {
ret |= u32::from(*item) << (i * 8);
i += 1;
}
Ok(ret)
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[cfg_attr(not(creusot), derive(Hash))]
pub enum PushDataLenLen {
One = 1,
Two = 2,
Four = 4,
}
impl PushDataLenLen {
#[cfg_attr(creusot, ensures(result@ == self@))]
fn to_usize(self) -> usize {
match self {
Self::One => 1,
Self::Two => 2,
Self::Four => 4,
}
}
}
impl Ord for PushDataLenLen {
#[cfg_attr(creusot, ensures(result == (*self).deep_model().cmp_log((*other).deep_model())))]
fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.to_usize().cmp(&other.to_usize()) }
}
impl PartialOrd for PushDataLenLen {
#[cfg_attr(creusot, ensures(result == (*self).deep_model().partial_cmp_log((*other).deep_model())))]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { Some(self.cmp(other)) }
}
#[cfg(creusot)]
impl View for PushDataLenLen {
type ViewTy = Int;
#[logic(open, inline)]
fn view(self) -> Self::ViewTy {
match self {
Self::One => 1,
Self::Two => 2,
Self::Four => 4,
}
}
}
#[cfg(creusot)]
impl DeepModel for PushDataLenLen {
type DeepModelTy = Int;
#[logic(open, inline)]
fn deep_model(self) -> Self::DeepModelTy { self.view() }
}
#[derive(Debug)]
pub struct EarlyEndOfScriptError;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reads_4_bytes() {
let bytes = [0x01, 0x23, 0x45, 0x67];
let want = u32::from_le_bytes([0x01, 0x23, 0x45, 0x67]);
let got = read_push_data_len(&mut bytes.iter(), PushDataLenLen::Four).unwrap();
assert_eq!(got, want);
}
#[test]
fn reads_2_bytes() {
let bytes = [0x01, 0x23];
let want = u16::from_le_bytes([0x01, 0x23]);
let got = read_push_data_len(&mut bytes.iter(), PushDataLenLen::Two).unwrap();
assert_eq!(got, u32::from(want));
}
#[test]
fn reads_1_byte() {
let bytes = [0x01];
let want = 0x01u32;
let got = read_push_data_len(&mut bytes.iter(), PushDataLenLen::One).unwrap();
assert_eq!(got, want);
}
}