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