#![warn(missing_docs)]
#![cfg_attr(feature = "no-std", no_std)]
#![cfg_attr(feature = "cpu", doc = "```")]
#![cfg_attr(not(feature = "cpu"), doc = "```ignore")]
use core::ffi::c_void;
pub use buffer::*;
pub use count::*;
pub use devices::*;
pub use error::*;
use flag::AllocFlag;
pub use graph::*;
#[cfg(feature = "cpu")]
pub use devices::cpu::CPU;
#[cfg(feature = "cuda")]
pub use devices::cuda::CUDA;
#[cfg(feature = "opencl")]
pub use devices::opencl::OpenCL;
#[cfg(feature = "wgpu")]
pub use devices::wgpu::WGPU;
#[cfg(feature = "stack")]
pub use devices::stack::Stack;
#[cfg(feature = "network")]
pub use devices::network::Network;
#[cfg(feature = "autograd")]
pub use autograd::*;
pub use unary::*;
#[cfg(feature = "cpu")]
#[macro_use]
pub mod exec_on_cpu;
pub mod devices;
mod buffer;
mod count;
mod error;
pub mod flag;
mod graph;
mod op_traits;
mod shape;
mod two_way_ops;
mod unary;
#[cfg(feature = "static-api")]
pub mod static_api;
#[cfg(feature = "autograd")]
pub mod autograd;
pub mod number;
pub use op_traits::*;
pub use shape::*;
pub use two_way_ops::*;
#[cfg(feature = "autograd")]
#[cfg(feature = "opt-cache")]
compile_error!("The `autograd` and `opt-cache` feature are currently incompatible.
This is because the logic for detecting if a forward buffer is used during gradient calculation isn't implemented yet.");
#[cfg(feature = "autograd")]
#[cfg(feature = "realloc")]
compile_error!("The `autograd` and `realloc` feature are incompatible.
The automatic differentiation system requires caching of buffers, which is deactivated when using the `realloc` feature.");
#[cfg(all(feature = "realloc", feature = "opt-cache"))]
compile_error!("A typical 'cache' does not exist when the `realloc` feature is enabled.");
pub trait PtrType {
fn size(&self) -> usize;
fn flag(&self) -> AllocFlag;
}
pub trait ShallowCopy {
unsafe fn shallow(&self) -> Self;
}
pub trait CommonPtrs<T> {
fn ptrs(&self) -> (*const T, *mut c_void, u64);
fn ptrs_mut(&mut self) -> (*mut T, *mut c_void, u64);
}
pub trait Device: Sized + 'static {
type Ptr<U, S: Shape>: PtrType;
type Cache: CacheAble<Self>;
fn new() -> crate::Result<Self>;
#[cfg_attr(feature = "cpu", doc = "```")]
#[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
fn buffer<'a, T, S: Shape, A>(&'a self, arr: A) -> Buffer<'a, T, Self, S>
where
Buffer<'a, T, Self, S>: From<(&'a Self, A)>,
{
Buffer::from((self, arr))
}
#[cfg_attr(all(feature = "cpu", not(feature = "realloc")), doc = "```")]
#[cfg_attr(all(not(feature = "cpu"), feature = "realloc"), doc = "```ignore")]
#[inline]
fn retrieve<T, S: Shape>(&self, len: usize, add_node: impl AddGraph) -> Buffer<T, Self, S>
where
for<'a> Self: Alloc<'a, T, S>,
{
Self::Cache::retrieve(self, len, add_node)
}
#[cfg(feature = "autograd")]
#[inline]
unsafe fn get_existing_buf<T, S: Shape>(&self, ident: Ident) -> Buffer<T, Self, S> {
Self::Cache::get_existing_buf(self, ident).expect("A matching Buffer does not exist.")
}
#[cfg(not(feature = "no-std"))]
#[inline]
fn remove(&self, ident: Ident) {
Self::Cache::remove(self, ident);
}
#[cfg(not(feature = "no-std"))]
#[inline]
fn add_to_cache<T, S: Shape>(&self, ptr: &Self::Ptr<T, S>) -> Option<Ident> {
Self::Cache::add_to_cache(self, ptr)
}
}
pub trait DevicelessAble<'a, T, S: Shape = ()>: Alloc<'a, T, S> {}
pub trait MainMemory: Device {
fn as_ptr<T, S: Shape>(ptr: &Self::Ptr<T, S>) -> *const T;
fn as_ptr_mut<T, S: Shape>(ptr: &mut Self::Ptr<T, S>) -> *mut T;
}
#[cfg_attr(feature = "cpu", doc = "```")]
#[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
pub trait Alloc<'a, T, S: Shape = ()>: Device {
#[cfg_attr(feature = "cpu", doc = "```")]
#[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
fn alloc(&'a self, len: usize, flag: AllocFlag) -> <Self as Device>::Ptr<T, S>;
#[cfg_attr(feature = "cpu", doc = "```")]
#[cfg_attr(not(feature = "cpu"), doc = "```ignore")]
fn with_slice(&'a self, data: &[T]) -> <Self as Device>::Ptr<T, S>
where
T: Clone;
#[inline]
#[cfg(not(feature = "no-std"))]
fn alloc_with_vec(&'a self, vec: Vec<T>) -> <Self as Device>::Ptr<T, S>
where
T: Clone,
{
self.with_slice(&vec)
}
#[inline]
fn with_array(&'a self, array: S::ARR<T>) -> <Self as Device>::Ptr<T, S>
where
T: Clone,
{
let stack_array = StackArray::<S, T>::from_array(array);
self.with_slice(stack_array.flatten())
}
}
#[cfg(feature = "autograd")]
pub trait MayTapeReturn: crate::TapeReturn {}
#[cfg(feature = "autograd")]
impl<D: crate::TapeReturn> MayTapeReturn for D {}
#[cfg(not(feature = "autograd"))]
pub trait MayTapeReturn {}
#[cfg(not(feature = "autograd"))]
impl<D> MayTapeReturn for D {}
#[cfg(not(unified_cl))]
pub const UNIFIED_CL_MEM: bool = false;
#[cfg(unified_cl)]
pub const UNIFIED_CL_MEM: bool = true;
#[cfg(feature = "macro")]
pub use custos_macro::impl_stack;
#[cfg(not(feature = "cpu"))]
pub struct CPU {
_uncreateable: (),
}
#[cfg(not(feature = "cpu"))]
impl Device for CPU {
type Ptr<U, S: Shape> = crate::Num<U>;
type Cache = ();
fn new() -> crate::Result<Self> {
#[cfg(feature = "no-std")]
{
unimplemented!("CPU is not available. Enable the `cpu` feature to use the CPU.")
}
#[cfg(not(feature = "no-std"))]
Err(crate::DeviceError::CPUDeviceNotAvailable.into())
}
}
pub mod prelude {
pub use crate::{
number::*, range, shape::*, Alloc, Buffer, CDatatype, ClearBuf, CopySlice, Device,
GraphReturn, Ident, MainMemory, MayTapeReturn, Read, ShallowCopy, WithShape, WriteBuf,
MayToCLSource
};
#[cfg(feature = "cpu")]
pub use crate::{exec_on_cpu::*, CPU};
#[cfg(not(feature = "no-std"))]
pub use crate::{cache::CacheReturn, get_count, set_count, Cache};
#[cfg(feature = "opencl")]
pub use crate::opencl::{enqueue_kernel, CLBuffer, OpenCL, CL};
#[cfg(feature = "opencl")]
#[cfg(unified_cl)]
#[cfg(not(feature = "realloc"))]
pub use crate::opencl::{construct_buffer, to_cached_unified};
#[cfg(feature = "stack")]
pub use crate::stack::Stack;
#[cfg(feature = "network")]
pub use crate::network::{Network, NetworkArray};
#[cfg(feature = "wgpu")]
pub use crate::wgpu::{launch_shader, WGPU};
#[cfg(feature = "cuda")]
pub use crate::cuda::{launch_kernel1d, CUBuffer, CU, CUDA};
}
#[cfg(test)]
mod tests {
#[cfg(feature = "cpu")]
#[test]
fn test_buffer_from_device() {
use crate::{Device, CPU};
let device = CPU::new();
let buf = device.buffer([1, 2, 3]);
assert_eq!(buf.read(), [1, 2, 3])
}
}