foundation_models/
error.rs1use core::ffi::c_char;
4use core::fmt;
5
6use crate::ffi;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10#[non_exhaustive]
11pub enum FMError {
12 ModelUnavailable {
16 reason: Unavailability,
17 message: String,
18 },
19 GuardrailViolation(String),
22 ContextWindowExceeded(String),
24 UnsupportedLanguage(String),
26 AssetsUnavailable(String),
28 RateLimited(String),
31 DecodingFailure(String),
34 Refusal(String),
37 ConcurrentRequests(String),
39 UnsupportedGuide(String),
41 Cancelled,
43 InvalidArgument(String),
45 Unknown { code: i32, message: String },
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52#[non_exhaustive]
53pub enum Unavailability {
54 DeviceNotEligible,
56 AppleIntelligenceNotEnabled,
58 ModelNotReady,
60 OsTooOld,
62 Unknown,
65}
66
67impl FMError {
68 #[must_use]
71 pub const fn code(&self) -> i32 {
72 match self {
73 Self::ModelUnavailable { .. } => ffi::status::MODEL_UNAVAILABLE,
74 Self::GuardrailViolation(_) => ffi::status::GUARDRAIL_VIOLATION,
75 Self::ContextWindowExceeded(_) => ffi::status::CONTEXT_WINDOW_EXCEEDED,
76 Self::UnsupportedLanguage(_) => ffi::status::UNSUPPORTED_LANGUAGE,
77 Self::AssetsUnavailable(_) => ffi::status::ASSETS_UNAVAILABLE,
78 Self::RateLimited(_) => ffi::status::RATE_LIMITED,
79 Self::DecodingFailure(_) => ffi::status::DECODING_FAILURE,
80 Self::Refusal(_) => ffi::status::REFUSAL,
81 Self::ConcurrentRequests(_) => ffi::status::CONCURRENT_REQUESTS,
82 Self::UnsupportedGuide(_) => ffi::status::UNSUPPORTED_GUIDE,
83 Self::Cancelled => ffi::status::CANCELLED,
84 Self::InvalidArgument(_) => ffi::status::INVALID_ARGUMENT,
85 Self::Unknown { code, .. } => *code,
86 }
87 }
88
89 #[must_use]
91 pub fn message(&self) -> &str {
92 match self {
93 Self::ModelUnavailable { message, .. }
94 | Self::GuardrailViolation(message)
95 | Self::ContextWindowExceeded(message)
96 | Self::UnsupportedLanguage(message)
97 | Self::AssetsUnavailable(message)
98 | Self::RateLimited(message)
99 | Self::DecodingFailure(message)
100 | Self::Refusal(message)
101 | Self::ConcurrentRequests(message)
102 | Self::UnsupportedGuide(message)
103 | Self::InvalidArgument(message)
104 | Self::Unknown { message, .. } => message,
105 Self::Cancelled => "generation cancelled",
106 }
107 }
108}
109
110impl fmt::Display for FMError {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 write!(f, "{} (code {})", self.message(), self.code())
113 }
114}
115
116impl std::error::Error for FMError {}
117
118pub(crate) unsafe fn from_swift(status: i32, error_str: *mut c_char) -> FMError {
123 let message = if error_str.is_null() {
124 String::new()
125 } else {
126 let s = core::ffi::CStr::from_ptr(error_str)
127 .to_string_lossy()
128 .into_owned();
129 ffi::fm_string_free(error_str);
130 s
131 };
132
133 match status {
134 ffi::status::MODEL_UNAVAILABLE => FMError::ModelUnavailable {
135 reason: Unavailability::Unknown,
136 message,
137 },
138 ffi::status::GUARDRAIL_VIOLATION => FMError::GuardrailViolation(message),
139 ffi::status::CONTEXT_WINDOW_EXCEEDED => FMError::ContextWindowExceeded(message),
140 ffi::status::UNSUPPORTED_LANGUAGE => FMError::UnsupportedLanguage(message),
141 ffi::status::ASSETS_UNAVAILABLE => FMError::AssetsUnavailable(message),
142 ffi::status::RATE_LIMITED => FMError::RateLimited(message),
143 ffi::status::DECODING_FAILURE => FMError::DecodingFailure(message),
144 ffi::status::REFUSAL => FMError::Refusal(message),
145 ffi::status::CONCURRENT_REQUESTS => FMError::ConcurrentRequests(message),
146 ffi::status::UNSUPPORTED_GUIDE => FMError::UnsupportedGuide(message),
147 ffi::status::CANCELLED => FMError::Cancelled,
148 ffi::status::INVALID_ARGUMENT => FMError::InvalidArgument(message),
149 code => FMError::Unknown { code, message },
150 }
151}