forked from Orchid/orchid
Significantly extended stdlib
This commit is contained in:
25
orchid-std/src/std/binary/binary_atom.rs
Normal file
25
orchid-std/src/std/binary/binary_atom.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use std::borrow::Cow;
|
||||
use std::pin::Pin;
|
||||
use std::rc::Rc;
|
||||
|
||||
use futures::AsyncWrite;
|
||||
use orchid_api_traits::Encode;
|
||||
use orchid_extension::atom::Atomic;
|
||||
use orchid_extension::atom_owned::{DeserializeCtx, OwnedAtom, OwnedVariant};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BlobAtom(pub(crate) Rc<Vec<u8>>);
|
||||
impl Atomic for BlobAtom {
|
||||
type Variant = OwnedVariant;
|
||||
type Data = ();
|
||||
}
|
||||
impl OwnedAtom for BlobAtom {
|
||||
type Refs = ();
|
||||
async fn val(&self) -> Cow<'_, Self::Data> { Cow::Owned(()) }
|
||||
async fn serialize(&self, write: Pin<&mut (impl AsyncWrite + ?Sized)>) -> Self::Refs {
|
||||
self.0.encode(write).await.unwrap()
|
||||
}
|
||||
async fn deserialize(mut dctx: impl DeserializeCtx, _: Self::Refs) -> Self {
|
||||
Self(dctx.read::<Rc<Vec<u8>>>().await)
|
||||
}
|
||||
}
|
||||
146
orchid-std/src/std/binary/binary_lib.rs
Normal file
146
orchid-std/src/std/binary/binary_lib.rs
Normal file
@@ -0,0 +1,146 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use orchid_base::error::{OrcErrv, mk_errv};
|
||||
use orchid_base::interner::is;
|
||||
use orchid_extension::atom::TAtom;
|
||||
use orchid_extension::atom_owned::own;
|
||||
use orchid_extension::func_atom::get_arg_posv;
|
||||
use orchid_extension::gen_expr::new_atom;
|
||||
use orchid_extension::tree::{GenMember, comments, fun, prefix};
|
||||
|
||||
use crate::std::binary::binary_atom::BlobAtom;
|
||||
use crate::std::boolean::Bool;
|
||||
use crate::{Int, OrcOpt, Tpl};
|
||||
|
||||
async fn bounds_error(
|
||||
expected: String,
|
||||
blob: &BlobAtom,
|
||||
args: impl IntoIterator<Item = usize>,
|
||||
) -> OrcErrv {
|
||||
mk_errv(
|
||||
is("Index out of bounds").await,
|
||||
format!("Selected {expected} from blob of len {}", blob.0.len()),
|
||||
get_arg_posv(args).await,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn gen_binary_lib() -> Vec<GenMember> {
|
||||
prefix("std", [comments(
|
||||
["A Blob is a sequence of bytes stored and processed efficiently."],
|
||||
prefix("binary", [
|
||||
comments(
|
||||
["Appends a binary blob to another", "|type: Blob -> Blob -> Blob|"],
|
||||
fun(true, "concat", async |a: TAtom<BlobAtom>, b: TAtom<BlobAtom>| {
|
||||
new_atom(BlobAtom(Rc::new(
|
||||
own(&a).await.0.iter().chain(&own(&b).await.0[..]).copied().collect(),
|
||||
)))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Copies out a subsection of the binary into a new blob \
|
||||
specified by starting point and length",
|
||||
"|type: Blob -> Int -> Int -> Blob|",
|
||||
],
|
||||
fun(true, "slice", async |a: TAtom<BlobAtom>, Int(start): Int, Int(len): Int| {
|
||||
let blob = own(&a).await;
|
||||
if start + len > blob.0.len() as i64 {
|
||||
return Err(bounds_error(format!("{start}+{len}"), &blob, 0..3).await);
|
||||
}
|
||||
let sub = blob.0[start as usize..(start + len) as usize].to_vec();
|
||||
Ok(new_atom(BlobAtom(Rc::new(sub))))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Return the index where the second binary appears as a subsection of the first",
|
||||
"|type: Blob -> Blob -> std::option Int|",
|
||||
],
|
||||
fun(true, "find", async |haystack: TAtom<BlobAtom>, needle: TAtom<BlobAtom>| {
|
||||
let haystack_vec = own(&haystack).await;
|
||||
let needle_vec = own(&needle).await;
|
||||
for i in 0..haystack_vec.0.len() - needle_vec.0.len() {
|
||||
if haystack_vec.0[i..].starts_with(&needle_vec.0) {
|
||||
return OrcOpt(Some(Int(i as i64)));
|
||||
}
|
||||
}
|
||||
OrcOpt(None)
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Splits the binary into two halves at the given byte index",
|
||||
"|type: Blob -> Int -> std::tuple Blob Blob|",
|
||||
],
|
||||
fun(true, "split", async |a: TAtom<BlobAtom>, i: Int| {
|
||||
let v = own(&a).await;
|
||||
if v.0.len() < i.0 as usize {
|
||||
return Err(bounds_error(i.0.to_string(), &v, 1..2).await);
|
||||
}
|
||||
let (l, r) = v.0.split_at(i.0 as usize);
|
||||
Ok(Tpl((
|
||||
new_atom(BlobAtom(Rc::new(l.to_vec()))),
|
||||
new_atom(BlobAtom(Rc::new(r.to_vec()))),
|
||||
)))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Takes a binary, a starting point, a length no greater than 8, and a boolean flag \
|
||||
which is true if the number is little endian. Reads a usize from \
|
||||
the specified location in the binary.",
|
||||
"|type: Blob -> Int -> Int -> Bool -> Int|",
|
||||
],
|
||||
fun(
|
||||
true,
|
||||
"get_int",
|
||||
async |bin: TAtom<BlobAtom>, Int(start): Int, Int(len): Int, Bool(le): Bool| {
|
||||
let vec = own(&bin).await;
|
||||
if start + len > vec.0.len() as i64 {
|
||||
return Err(bounds_error(format!("{start}+{len}"), &vec, 1..3).await);
|
||||
}
|
||||
if 8 < len {
|
||||
return Err(mk_errv(
|
||||
is("Too many bytes for int conversion").await,
|
||||
format!("At most 8 bytes fit into an Int, requested {len}"),
|
||||
get_arg_posv(3..4).await,
|
||||
));
|
||||
}
|
||||
let slice = &vec.0[start as usize..(start + len) as usize];
|
||||
let mut data = [0u8; 8];
|
||||
Ok(Int(if le {
|
||||
data[..len as usize].copy_from_slice(slice);
|
||||
i64::from_le_bytes(data)
|
||||
} else {
|
||||
data[(8 - len as usize)..].copy_from_slice(slice);
|
||||
i64::from_be_bytes(data)
|
||||
}))
|
||||
},
|
||||
),
|
||||
),
|
||||
comments(
|
||||
[
|
||||
"Takes a length no greater than int_bytes, a little endian flag and a number to encode. \
|
||||
Turns the least significant bytes of the given int into a binary.",
|
||||
"|type: Int -> Bool -> Int -> Blob|",
|
||||
],
|
||||
fun(true, "from_num", async |len: Int, le: Bool, val: Int| {
|
||||
if 8 < len.0 {
|
||||
return Err(mk_errv(
|
||||
is("Too many bytes for int conversion").await,
|
||||
format!("Ints are 8 bytes, attempted to write {} byte buffer", len.0),
|
||||
get_arg_posv(0..1).await,
|
||||
));
|
||||
}
|
||||
let data = if le.0 { val.0.to_le_bytes() } else { val.0.to_be_bytes() };
|
||||
let data = if le.0 { &data[..len.0 as usize] } else { &data[(8 - len.0 as usize)..] };
|
||||
Ok(new_atom(BlobAtom(Rc::new(data.to_vec()))))
|
||||
}),
|
||||
),
|
||||
comments(
|
||||
["Returns the number of bytes in a binary", "|type: Blob -> Int|"],
|
||||
fun(true, "size", async |blob: TAtom<BlobAtom>| Int(own(&blob).await.0.len() as i64)),
|
||||
),
|
||||
]),
|
||||
)])
|
||||
}
|
||||
2
orchid-std/src/std/binary/mod.rs
Normal file
2
orchid-std/src/std/binary/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod binary_atom;
|
||||
pub mod binary_lib;
|
||||
Reference in New Issue
Block a user