Skip to content

Commit

Permalink
lib: clarify send + sync status
Browse files Browse the repository at this point in the history
  • Loading branch information
chyyran committed Sep 5, 2024
1 parent 5b619ca commit a62a90e
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 8 deletions.
5 changes: 5 additions & 0 deletions spirv-cross2/src/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,11 @@ pub struct CompiledArtifact<'a, T> {
source: ContextStr<'a>,
}

// SAFETY: SpirvCrossContext is Send.
// CompiledArtifact is immutable.
unsafe impl<T> Send for CompiledArtifact<'_, T> {}
unsafe impl<T> Sync for CompiledArtifact<'_, T> {}

impl<T> AsRef<str> for CompiledArtifact<'_, T> {
fn as_ref(&self) -> &str {
self.source.as_ref()
Expand Down
6 changes: 5 additions & 1 deletion spirv-cross2/src/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ pub use spirv_cross_sys::VariableId;
#[repr(transparent)]
struct PointerOnlyForComparison<T>(NonNull<T>);

// SAFETY: pointer is only for comparison.
unsafe impl<T> Send for PointerOnlyForComparison<T> {}
unsafe impl<T> Sync for PointerOnlyForComparison<T> {}

impl<T> PartialEq for PointerOnlyForComparison<T> {
fn eq(&self, other: &Self) -> bool {
other.0.as_ptr() == self.0.as_ptr()
Expand Down Expand Up @@ -63,7 +67,7 @@ impl<T: Id> Handle<T> {
}

/// Trait for SPIRV-Cross ID types.
pub trait Id: Sealed + Debug + 'static {
pub trait Id: Sealed + Debug + Send + Sync + 'static {
/// Return the `u32` part of the Id.
fn id(&self) -> u32;
}
Expand Down
30 changes: 24 additions & 6 deletions spirv-cross2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ use crate::targets::Target;
use std::marker::PhantomData;
use std::ops::Deref;
use std::ptr::NonNull;
use std::rc::Rc;
use std::sync::Arc;

/// Compilation of SPIR-V to a textual format.
pub mod compile;
Expand Down Expand Up @@ -173,6 +173,15 @@ pub use crate::string::ContextStr;
#[repr(transparent)]
pub struct SpirvCrossContext(NonNull<spvc_context_s>);

// SAFETY: SpirvCrossContext is not clone.
//
// While allocations are interior mutability,
// they should be safe one thread at a time.
//
// C++ new and delete operators are thread safe,
// which is what this uses to allocate.s
unsafe impl Send for SpirvCrossContext {}

/// The root lifetime of a SPIRV-Cross context.
///
/// There are mainly two lifetimes to worry about in the entire crate,
Expand All @@ -195,14 +204,14 @@ pub struct SpirvCrossContext(NonNull<spvc_context_s>);
/// matches the lifetime of the immutable borrow of the compiler.
enum ContextRoot<'a, T = SpirvCrossContext> {
Borrowed(&'a T),
RefCounted(Rc<T>),
RefCounted(Arc<T>),
}

impl<'a, T> Clone for ContextRoot<'a, T> {
fn clone(&self) -> Self {
match self {
&ContextRoot::Borrowed(a) => ContextRoot::Borrowed(a),
ContextRoot::RefCounted(rc) => ContextRoot::RefCounted(Rc::clone(rc)),
ContextRoot::RefCounted(rc) => ContextRoot::RefCounted(Arc::clone(rc)),
}
}
}
Expand Down Expand Up @@ -312,7 +321,7 @@ impl SpirvCrossContext {
/// pointer to the SPIRV-Cross context, and thus has a `'static`
/// lifetime.
pub fn create_compiler_refcounted<T: Target>(
self: &Rc<Self>,
self: &Arc<Self>,
spirv: Module,
) -> error::Result<Compiler<'static, T>> {
unsafe {
Expand Down Expand Up @@ -341,7 +350,7 @@ impl SpirvCrossContext {

Ok(Compiler::new_from_raw(
compiler,
ContextRoot::RefCounted(Rc::clone(self)),
ContextRoot::RefCounted(Arc::clone(self)),
))
}
}
Expand Down Expand Up @@ -380,7 +389,7 @@ impl SpirvCrossContext {

Ok(Compiler::new_from_raw(
compiler,
ContextRoot::RefCounted(Rc::new(self)),
ContextRoot::RefCounted(Arc::new(self)),
))
}
}
Expand Down Expand Up @@ -434,6 +443,15 @@ pub struct Compiler<'a, T> {
_pd: PhantomData<T>,
}

// SAFETY: Compiler is not clone.
//
// While allocations are interior mutability,
// they should be safe one thread at a time.
//
// C++ new and delete operators are thread safe,
// which is what this uses to allocate.s
unsafe impl<T> Send for Compiler<'_, T> {}

impl<T> Compiler<'_, T> {
/// Create a new compiler instance.
///
Expand Down
10 changes: 9 additions & 1 deletion spirv-cross2/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ pub struct ContextStr<'a, T = SpirvCrossContext> {
cow: Cow<'a, str>,
}

// SAFETY: SpirvCrossContext is Send.
// Once created, the ContextStr is immutable, so it is also sync.
// cloning the string doesn't affect the memory, as long as it
// is alive for 'a.
unsafe impl<T: Send> Send for ContextStr<'_, T> {}
unsafe impl<T: Send> Sync for ContextStr<'_, T> {}

impl<T> Clone for ContextStr<'_, T> {
fn clone(&self) -> Self {
Self {
Expand Down Expand Up @@ -308,6 +315,7 @@ mod test {
use crate::ContextRoot;
use std::ffi::{c_char, CStr, CString};
use std::rc::Rc;
use std::sync::Arc;

struct LifetimeContext(*mut c_char);
impl LifetimeContext {
Expand Down Expand Up @@ -341,7 +349,7 @@ mod test {
fn test_string() {
// use std::borrow::BorrowMut;
let lc = LifetimeContext::new();
let ctx = ContextRoot::RefCounted(Rc::new(lc));
let ctx = ContextRoot::RefCounted(Arc::new(lc));

let mut lt = LifetimeTest(ctx);

Expand Down

0 comments on commit a62a90e

Please sign in to comment.