1use core::ptr;
2
3use serde::Deserialize;
4
5use crate::error::StoreKitError;
6use crate::ffi;
7use crate::private::{
8 cstring_from_str, error_from_status, parse_json_ptr, parse_optional_json_ptr,
9};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum ExternalPurchaseNoticeResult {
14 Continued,
16 Cancelled,
18 ContinuedWithExternalPurchaseToken {
20 token: String,
22 },
23 Unknown(String),
25}
26
27impl ExternalPurchaseNoticeResult {
28 pub fn as_str(&self) -> &str {
30 match self {
31 Self::Continued => "continued",
32 Self::Cancelled => "cancelled",
33 Self::ContinuedWithExternalPurchaseToken { .. } => "continuedWithExternalPurchaseToken",
34 Self::Unknown(value) => value.as_str(),
35 }
36 }
37}
38
39#[derive(Debug, Clone, Copy, Default)]
40pub struct ExternalPurchase;
42
43impl ExternalPurchase {
44 pub fn can_present() -> Result<bool, StoreKitError> {
46 let mut raw_value = 0;
47 let mut error_message = ptr::null_mut();
48 let status =
49 unsafe { ffi::sk_external_purchase_can_present(&mut raw_value, &mut error_message) };
50 if status == ffi::status::OK {
51 Ok(raw_value != 0)
52 } else {
53 Err(unsafe { error_from_status(status, error_message) })
54 }
55 }
56
57 pub fn present_notice_sheet() -> Result<ExternalPurchaseNoticeResult, StoreKitError> {
59 let mut result_json = ptr::null_mut();
60 let mut error_message = ptr::null_mut();
61 let status = unsafe {
62 ffi::sk_external_purchase_present_notice_result_json(
63 &mut result_json,
64 &mut error_message,
65 )
66 };
67 if status != ffi::status::OK {
68 return Err(unsafe { error_from_status(status, error_message) });
69 }
70 let payload = unsafe {
71 parse_json_ptr::<ExternalPurchaseNoticeResultPayload>(
72 result_json,
73 "external purchase notice result",
74 )
75 }?;
76 Ok(payload.into_notice_result())
77 }
78}
79
80#[derive(Debug, Clone, Copy, Default)]
81pub struct ExternalPurchaseLink;
83
84impl ExternalPurchaseLink {
85 pub fn can_open() -> Result<bool, StoreKitError> {
87 let mut raw_value = 0;
88 let mut error_message = ptr::null_mut();
89 let status =
90 unsafe { ffi::sk_external_purchase_link_can_open(&mut raw_value, &mut error_message) };
91 if status == ffi::status::OK {
92 Ok(raw_value != 0)
93 } else {
94 Err(unsafe { error_from_status(status, error_message) })
95 }
96 }
97
98 pub fn eligible_urls() -> Result<Option<Vec<String>>, StoreKitError> {
100 let mut urls_json = ptr::null_mut();
101 let mut error_message = ptr::null_mut();
102 let status = unsafe {
103 ffi::sk_external_purchase_link_eligible_urls_json(&mut urls_json, &mut error_message)
104 };
105 if status != ffi::status::OK {
106 return Err(unsafe { error_from_status(status, error_message) });
107 }
108 unsafe {
109 parse_optional_json_ptr::<Vec<String>>(urls_json, "eligible external purchase URLs")
110 }
111 }
112
113 pub fn open() -> Result<(), StoreKitError> {
115 let mut error_message = ptr::null_mut();
116 let status = unsafe { ffi::sk_external_purchase_link_open(&mut error_message) };
117 if status == ffi::status::OK {
118 Ok(())
119 } else {
120 Err(unsafe { error_from_status(status, error_message) })
121 }
122 }
123
124 pub fn open_url(url: &str) -> Result<(), StoreKitError> {
126 let url = cstring_from_str(url, "external purchase URL")?;
127 let mut error_message = ptr::null_mut();
128 let status =
129 unsafe { ffi::sk_external_purchase_link_open_url(url.as_ptr(), &mut error_message) };
130 if status == ffi::status::OK {
131 Ok(())
132 } else {
133 Err(unsafe { error_from_status(status, error_message) })
134 }
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum ExternalPurchaseCustomLinkNoticeType {
141 WithinApp,
143 Browser,
145 Unknown(i64),
147}
148
149impl ExternalPurchaseCustomLinkNoticeType {
150 pub const fn as_raw(&self) -> i64 {
152 match self {
153 Self::WithinApp => 0,
154 Self::Browser => 1,
155 Self::Unknown(value) => *value,
156 }
157 }
158}
159
160#[derive(Debug, Clone, PartialEq, Eq)]
161pub enum ExternalPurchaseCustomLinkNoticeResult {
163 Cancelled,
165 Continued,
167 Unknown(String),
169}
170
171impl ExternalPurchaseCustomLinkNoticeResult {
172 pub fn as_str(&self) -> &str {
174 match self {
175 Self::Cancelled => "cancelled",
176 Self::Continued => "continued",
177 Self::Unknown(value) => value.as_str(),
178 }
179 }
180}
181
182#[derive(Debug, Clone, PartialEq, Eq)]
183pub struct ExternalPurchaseCustomLinkToken {
185 pub value: String,
187}
188
189#[derive(Debug, Clone, Copy, Default)]
190pub struct ExternalPurchaseCustomLink;
192
193impl ExternalPurchaseCustomLink {
194 pub fn is_eligible() -> Result<bool, StoreKitError> {
196 let mut raw_value = 0;
197 let mut error_message = ptr::null_mut();
198 let status = unsafe {
199 ffi::sk_external_purchase_custom_link_is_eligible(&mut raw_value, &mut error_message)
200 };
201 if status == ffi::status::OK {
202 Ok(raw_value != 0)
203 } else {
204 Err(unsafe { error_from_status(status, error_message) })
205 }
206 }
207
208 pub fn show_notice(
210 notice_type: ExternalPurchaseCustomLinkNoticeType,
211 ) -> Result<ExternalPurchaseCustomLinkNoticeResult, StoreKitError> {
212 let raw_notice_type = i32::try_from(notice_type.as_raw()).map_err(|_| {
213 StoreKitError::InvalidArgument(format!(
214 "external purchase custom link notice type '{}' does not fit in i32",
215 notice_type.as_raw()
216 ))
217 })?;
218 let mut result_json = ptr::null_mut();
219 let mut error_message = ptr::null_mut();
220 let status = unsafe {
221 ffi::sk_external_purchase_custom_link_show_notice_result_json(
222 raw_notice_type,
223 &mut result_json,
224 &mut error_message,
225 )
226 };
227 if status != ffi::status::OK {
228 return Err(unsafe { error_from_status(status, error_message) });
229 }
230 let payload = unsafe {
231 parse_json_ptr::<ExternalPurchaseCustomLinkNoticeResultPayload>(
232 result_json,
233 "external purchase custom link notice result",
234 )
235 }?;
236 Ok(payload.into_notice_result())
237 }
238
239 pub fn token(
241 token_type: &str,
242 ) -> Result<Option<ExternalPurchaseCustomLinkToken>, StoreKitError> {
243 let token_type = cstring_from_str(token_type, "external purchase custom link token type")?;
244 let mut token_json = ptr::null_mut();
245 let mut error_message = ptr::null_mut();
246 let status = unsafe {
247 ffi::sk_external_purchase_custom_link_token_json(
248 token_type.as_ptr(),
249 &mut token_json,
250 &mut error_message,
251 )
252 };
253 if status != ffi::status::OK {
254 return Err(unsafe { error_from_status(status, error_message) });
255 }
256 unsafe {
257 parse_optional_json_ptr::<ExternalPurchaseCustomLinkTokenPayload>(
258 token_json,
259 "external purchase custom link token",
260 )
261 }
262 .map(|payload| {
263 payload.map(|payload| ExternalPurchaseCustomLinkToken {
264 value: payload.value,
265 })
266 })
267 }
268}
269
270#[derive(Debug, Deserialize)]
271struct ExternalPurchaseNoticeResultPayload {
272 kind: String,
273 token: Option<String>,
274}
275
276impl ExternalPurchaseNoticeResultPayload {
277 fn into_notice_result(self) -> ExternalPurchaseNoticeResult {
278 match self.kind.as_str() {
279 "continued" => ExternalPurchaseNoticeResult::Continued,
280 "cancelled" => ExternalPurchaseNoticeResult::Cancelled,
281 "continuedWithExternalPurchaseToken" => {
282 ExternalPurchaseNoticeResult::ContinuedWithExternalPurchaseToken {
283 token: self.token.unwrap_or_default(),
284 }
285 }
286 other => ExternalPurchaseNoticeResult::Unknown(other.to_owned()),
287 }
288 }
289}
290
291#[derive(Debug, Deserialize)]
292struct ExternalPurchaseCustomLinkNoticeResultPayload {
293 kind: String,
294}
295
296impl ExternalPurchaseCustomLinkNoticeResultPayload {
297 fn into_notice_result(self) -> ExternalPurchaseCustomLinkNoticeResult {
298 match self.kind.as_str() {
299 "cancelled" => ExternalPurchaseCustomLinkNoticeResult::Cancelled,
300 "continued" => ExternalPurchaseCustomLinkNoticeResult::Continued,
301 other => ExternalPurchaseCustomLinkNoticeResult::Unknown(other.to_owned()),
302 }
303 }
304}
305
306#[derive(Debug, Deserialize)]
307struct ExternalPurchaseCustomLinkTokenPayload {
308 value: String,
309}