use std::fmt;
use std::fs;
use std::path::Path;
use crate::archive;
use crate::error::Result;
#[derive(Clone, PartialEq, Eq)]
pub struct Weights {
bytes: Vec<u8>,
generation: u8,
}
impl Weights {
pub fn from_bytes<B>(bytes: B) -> Result<Self>
where
B: Into<Vec<u8>>,
{
let bytes = bytes.into();
archive::check_magic(&bytes)?;
Ok(Weights {
bytes,
generation: 3,
})
}
pub fn from_file<P>(path: P) -> Result<Self>
where
P: AsRef<Path>,
{
Self::from_bytes(fs::read(path.as_ref())?)
}
#[inline]
#[must_use]
pub fn len(&self) -> usize {
self.bytes.len()
}
#[inline]
#[must_use]
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
#[inline]
#[must_use]
pub const fn generation(&self) -> u8 {
self.generation
}
pub(crate) fn as_bytes(&self) -> &[u8] {
&self.bytes
}
}
impl fmt::Debug for Weights {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Weights")
.field("generation", &self.generation)
.field("len", &self.bytes.len())
.finish()
}
}
#[cfg(feature = "download")]
#[cfg_attr(docsrs, doc(cfg(feature = "download")))]
pub const WEIGHTS_SHA256: &str = "c9d915eca282ed42d1a09b143b592adb4cc6744ffe2d294adf5cfc5548170c38";
#[cfg(feature = "download")]
pub(crate) const PIN: crate::download::Pin = crate::download::Pin {
repo: "Cactus-Compute/needle3",
revision: cactus_sys::NEEDLE_ENGINE_COMMIT,
file: "needle3.cact",
sha256: WEIGHTS_SHA256,
env: "CACTUS_NEEDLE_WEIGHTS",
cache_dir: "needle3",
};
#[cfg(feature = "download")]
impl Weights {
#[cfg_attr(docsrs, doc(cfg(feature = "download")))]
pub fn fetch() -> Result<Self> {
Weights::from_bytes(crate::download::fetch(&PIN)?)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::Error;
#[test]
fn generation_three_is_accepted() {
let weights = Weights::from_bytes(vec![0x84, 0x2A, 0xE1, 0x05, 0x45]).expect("gen 3 tag");
assert_eq!(weights.generation(), 3);
assert_eq!(weights.len(), 5);
}
const MAGIC_GENERATION_2: u32 = 0x05E1_2A83;
#[test]
fn generation_two_is_rejected_by_tag() {
let error = Weights::from_bytes(vec![0x83, 0x2A, 0xE1, 0x05]).expect_err("gen 2 tag");
assert!(matches!(
error,
Error::UnsupportedWeights {
tag: MAGIC_GENERATION_2
}
));
}
#[test]
fn a_short_file_is_not_an_archive() {
let error = Weights::from_bytes(vec![0x84, 0x2A]).expect_err("truncated header");
assert!(matches!(error, Error::UnsupportedWeights { tag: 0 }));
}
#[test]
fn debug_does_not_dump_the_bytes() {
let weights = Weights::from_bytes(vec![0x84, 0x2A, 0xE1, 0x05, 0xAB]).expect("gen 3 tag");
let text = format!("{weights:?}");
assert_eq!(text, "Weights { generation: 3, len: 5 }");
}
}