risc0_sppark/
lib.rs

1// Copyright Supranational LLC
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#![allow(unexpected_cfgs)]
6
7// Declare C/C++ counterpart as following:
8// extern "C" { fn foobar(...) -> sppark::Error; }
9#[repr(C)]
10pub struct Error {
11    pub code: i32,
12    str: Option<core::ptr::NonNull<i8>>, // just strdup("string") from C/C++
13}
14
15impl Drop for Error {
16    fn drop(&mut self) {
17        extern "C" {
18            fn free(str: Option<core::ptr::NonNull<i8>>);
19        }
20        unsafe { free(self.str) };
21        self.str = None;
22    }
23}
24
25impl From<&Error> for String {
26    fn from(status: &Error) -> Self {
27        if let Some(str) = status.str {
28            let c_str = unsafe { std::ffi::CStr::from_ptr(str.as_ptr() as *const _) };
29            String::from(c_str.to_str().unwrap_or("unintelligible"))
30        } else {
31            format!("sppark::Error #{}", status.code)
32        }
33    }
34}
35
36impl From<Error> for String {
37    fn from(status: Error) -> Self {
38        String::from(&status)
39    }
40}
41
42impl std::fmt::Display for Error {
43    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
44        write!(f, "{}", String::from(self))
45    }
46}
47
48#[macro_export]
49macro_rules! cuda_error {
50    // legacy macro, deprecated
51    () => {
52        mod cuda {
53            pub type Error = sppark::Error;
54        }
55    };
56}
57
58use core::ffi::c_void;
59#[cfg(any(feature = "cuda", feature = "rocm"))]
60use core::mem::transmute;
61
62#[repr(C)]
63pub struct Gpu_Ptr<T> {
64    ptr: *const c_void,
65    phantom: core::marker::PhantomData<T>,
66}
67
68#[cfg(any(feature = "cuda", feature = "rocm"))]
69impl<T> Default for Gpu_Ptr<T> {
70    fn default() -> Self {
71        Self {
72            ptr: core::ptr::null(),
73            phantom: core::marker::PhantomData,
74        }
75    }
76}
77
78#[cfg(any(feature = "cuda", feature = "rocm"))]
79impl<T> Drop for Gpu_Ptr<T> {
80    fn drop(&mut self) {
81        extern "C" {
82            fn drop_gpu_ptr_t(by_ref: &Gpu_Ptr<c_void>);
83        }
84        unsafe { drop_gpu_ptr_t(transmute::<&_, &_>(self)) };
85        self.ptr = core::ptr::null();
86    }
87}
88
89#[cfg(any(feature = "cuda", feature = "rocm"))]
90impl<T> Clone for Gpu_Ptr<T> {
91    fn clone(&self) -> Self {
92        extern "C" {
93            fn clone_gpu_ptr_t(by_ref: &Gpu_Ptr<c_void>) -> Gpu_Ptr<c_void>;
94        }
95        unsafe { transmute::<_, _>(clone_gpu_ptr_t(transmute::<&_, &_>(self))) }
96    }
97}
98
99#[repr(C)]
100pub enum NTTInputOutputOrder {
101    NN = 0,
102    NR = 1,
103    RN = 2,
104    RR = 3,
105}
106
107#[repr(C)]
108pub enum NTTDirection {
109    Forward = 0,
110    Inverse = 1,
111}
112
113#[repr(C)]
114pub enum NTTType {
115    Standard = 0,
116    Coset = 1,
117}
118
119// Given `slice_t<U>` value argument on the C++ side, one declares
120// corresponding argument as `sppark::Slice<U>` on the Rust side and
121// passes Rust slice as `foo.into()`. Recall that `U` has to be concrete
122// on the FFI boundary. This can be tricky if the Rust side is generic.
123// If the concrete type is not readily available in Rust, use a stand-in
124// such as `sppark::Slice<[u64; N]>` with N chosen to match the size of
125// the object. Note that all below methods use raw pointer casts, yet
126// there are no `unsafe` blocks. Rationale is that one would invoke them
127// as one passes arguments to an FFI interface, which has to be in an
128// unsafe block already.
129
130#[repr(C)]
131pub struct Slice<U> {
132    ptr: *const U,
133    len: usize,
134}
135
136use core::mem::size_of;
137
138impl<T, U> From<&mut [T]> for Slice<U> {
139    #[inline]
140    fn from(slice: &mut [T]) -> Self {
141        // const _: () = // I wish this worked with generics:-(
142        assert!(size_of::<T>() == size_of::<U>());
143        Self {
144            ptr: slice.as_mut_ptr() as *mut _,
145            len: slice.len(),
146        }
147    }
148}
149
150impl<T, U> From<&[T]> for Slice<U> {
151    #[inline]
152    fn from(slice: &[T]) -> Self {
153        // const _: () = // I wish this worked with generics:-(
154        assert!(size_of::<T>() == size_of::<U>());
155        Self {
156            ptr: slice.as_ptr() as *const _,
157            len: slice.len(),
158        }
159    }
160}
161
162impl<U> Slice<U> {
163    #[inline]
164    pub fn new<T>(p: *const T, n: usize) -> Self {
165        // const _: () = // I wish this worked with generics:-(
166        assert!(size_of::<T>() == size_of::<U>());
167        Self {
168            ptr: p as *const _,
169            len: n,
170        }
171    }
172}