1use std::fmt;
13use std::str::FromStr;
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19#[cfg_attr(
20 feature = "serde",
21 derive(serde::Serialize, serde::Deserialize),
22 serde(into = "String", try_from = "String")
23)]
24pub enum Device {
25 Cpu,
27 Cuda(usize),
30 Meta,
33}
34
35impl FromStr for Device {
36 type Err = DeviceError;
37
38 fn from_str(s: &str) -> Result<Self, Self::Err> {
41 if s.is_empty() {
42 return Err(DeviceError::Malformed(s.to_string()));
43 }
44 let (kind, index) = match s.split_once(':') {
45 Some((kind, index)) => (kind, Some(index)),
46 None => (s, None),
47 };
48 match (kind, index) {
49 ("cpu", None) => Ok(Self::Cpu),
50 ("meta", None) => Ok(Self::Meta),
51 ("cuda", Some(index)) => index
52 .parse()
53 .map(Self::Cuda)
54 .map_err(|_| DeviceError::Malformed(s.to_string())),
55 ("cuda", None) => Err(DeviceError::NeedsIndex(kind.to_string())),
56 ("cpu" | "meta", Some(_)) => Err(DeviceError::Malformed(s.to_string())),
57 _ => Err(DeviceError::Unknown(kind.to_string())),
58 }
59 }
60}
61
62impl From<Device> for String {
63 fn from(device: Device) -> Self {
64 device.to_string()
65 }
66}
67
68impl TryFrom<String> for Device {
69 type Error = DeviceError;
70
71 fn try_from(s: String) -> Result<Self, Self::Error> {
72 s.parse()
73 }
74}
75
76impl fmt::Display for Device {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 match self {
79 Self::Cpu => f.write_str("cpu"),
80 Self::Cuda(index) => write!(f, "cuda:{index}"),
81 Self::Meta => f.write_str("meta"),
82 }
83 }
84}
85
86#[derive(Debug, Clone, PartialEq, Eq)]
88pub enum DeviceError {
89 Unknown(String),
91 Malformed(String),
93 NeedsIndex(String),
95}
96
97impl fmt::Display for DeviceError {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 match self {
100 Self::Unknown(kind) => write!(
101 f,
102 "unknown device `{kind}`; today there are `cpu`, `cuda:N` and `meta`"
103 ),
104 Self::Malformed(s) => write!(
105 f,
106 "`{s}` is not shaped like a device; write `cpu`, `cuda:N` or `meta`"
107 ),
108 Self::NeedsIndex(kind) => write!(
109 f,
110 "`{kind}` does not say which one: write `{kind}:0`. \"The current one\" \
111 is thread state, not a placement"
112 ),
113 }
114 }
115}
116
117impl std::error::Error for DeviceError {}