Skip to content

Instantly share code, notes, and snippets.

@IAmJSD
Created February 24, 2024 17:35
Show Gist options
  • Save IAmJSD/3972dc739626f8e24a128acb7d953a07 to your computer and use it in GitHub Desktop.
Save IAmJSD/3972dc739626f8e24a128acb7d953a07 to your computer and use it in GitHub Desktop.
use std::thread;
// A container that holds data and the thread ID of the thread that created the container. Note that
// this container must be dropped in the same thread that created it, otherwise this will panic since
// the thread ID will be different.
pub struct ThreadBoundContainer<T> {
data: T,
thread_id: thread::ThreadId,
}
impl<T> ThreadBoundContainer<T> {
// Creates a new container with the given data.
pub fn new(data: T) -> ThreadBoundContainer<T> {
ThreadBoundContainer {
data,
thread_id: thread::current().id(),
}
}
// Gets a reference to the data if the current thread is the same as the one that created the container.
pub fn as_ref(&self) -> Result<&T, &'static str> {
if self.thread_id == thread::current().id() {
Ok(&self.data)
} else {
Err("Data accessed from wrong thread")
}
}
// Gets a mutable reference to the data if the current thread is the same as the one that created the container.
pub fn as_mut(&mut self) -> Result<&mut T, &'static str> {
if self.thread_id == thread::current().id() {
Ok(&mut self.data)
} else {
Err("Data accessed from wrong thread")
}
}
}
// This is safe to pass between threads because the data is not accessible from other threads.
unsafe impl<T> Send for ThreadBoundContainer<T> {}
unsafe impl<T> Sync for ThreadBoundContainer<T> {}
// Implements drop. Note that this will panic if the container is dropped in a different thread than
// the one that created it.
impl<T> Drop for ThreadBoundContainer<T> {
fn drop(&mut self) {
assert_eq!(self.thread_id, thread::current().id());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment