1use std::cell::Cell;
4use std::fmt;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum DeviceKind {
9 Cpu,
11 Gpu,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub struct Device {
18 pub kind: DeviceKind,
20 pub index: u32,
22}
23
24impl Device {
25 pub const fn cpu() -> Self {
27 Self {
28 kind: DeviceKind::Cpu,
29 index: 0,
30 }
31 }
32
33 pub const fn gpu(index: u32) -> Self {
35 Self {
36 kind: DeviceKind::Gpu,
37 index,
38 }
39 }
40}
41
42impl fmt::Display for Device {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self.kind {
45 DeviceKind::Cpu => write!(f, "cpu:{}", self.index),
46 DeviceKind::Gpu => write!(f, "gpu:{}", self.index),
47 }
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
53pub struct Stream {
54 pub index: u32,
56 pub device: Device,
58}
59
60impl Stream {
61 pub const fn default_for(device: Device) -> Self {
63 Self { index: 0, device }
64 }
65}
66
67thread_local! {
68 static DEFAULT_STREAM: Cell<Option<Stream>> = const { Cell::new(None) };
69}
70
71pub fn default_device() -> Device {
73 if crate::gpu::available() {
74 Device::gpu(0)
75 } else {
76 Device::cpu()
77 }
78}
79
80pub fn default_stream() -> Stream {
83 DEFAULT_STREAM.get().unwrap_or_else(|| {
84 let stream = Stream::default_for(default_device());
85 DEFAULT_STREAM.set(Some(stream));
86 stream
87 })
88}
89
90pub fn set_default_stream(stream: Stream) {
92 DEFAULT_STREAM.set(Some(stream));
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn default_is_the_default_device_and_settable_per_thread() {
101 assert_eq!(default_stream().device, default_device());
102 let expected = if cfg!(all(target_os = "macos", not(miri))) && crate::gpu::available() {
103 Device::gpu(0)
104 } else {
105 Device::cpu()
106 };
107 assert_eq!(default_device(), expected);
108 set_default_stream(Stream::default_for(Device::cpu()));
109 assert_eq!(default_stream().device, Device::cpu());
110 std::thread::spawn(|| assert_eq!(default_stream().device, default_device()))
111 .join()
112 .unwrap();
113 }
114
115 #[test]
116 fn display() {
117 assert_eq!(Device::gpu(1).to_string(), "gpu:1");
118 }
119}