storekit/
purchase_option.rs1use serde::{Deserialize, Serialize};
2
3use crate::error::StoreKitError;
4use crate::transaction::{Transaction, TransactionPayload};
5use crate::verification_result::{VerificationResult, VerificationResultPayload};
6
7#[derive(Debug, Clone, PartialEq, Serialize)]
8#[serde(tag = "kind", rename_all = "camelCase")]
9pub enum PurchaseOption {
10 AppAccountToken {
11 app_account_token: String,
12 },
13 Quantity {
14 quantity: i64,
15 },
16 SimulatesAskToBuyInSandbox {
17 simulate_ask_to_buy_in_sandbox: bool,
18 },
19 CustomString {
20 key: String,
21 value: String,
22 },
23 CustomNumber {
24 key: String,
25 value: f64,
26 },
27 CustomBool {
28 key: String,
29 value: bool,
30 },
31 CustomData {
32 key: String,
33 value_base64: String,
34 },
35 PromotionalOfferSignature {
36 offer_id: String,
37 key_id: String,
38 nonce: String,
39 signature_base64: String,
40 timestamp: i64,
41 },
42 PromotionalOfferCompactJws {
43 offer_id: String,
44 compact_jws: String,
45 },
46 IntroductoryOfferEligibility {
47 compact_jws: String,
48 },
49 WinBackOffer {
50 offer_id: String,
51 },
52 OnStorefrontChange {
53 should_continue_purchase: bool,
54 },
55}
56
57#[allow(clippy::large_enum_variant)]
58#[derive(Debug)]
59pub enum PurchaseResult {
60 Success(VerificationResult<Transaction>),
61 UserCancelled,
62 Pending,
63}
64
65#[allow(clippy::unsafe_derive_deserialize)]
66#[derive(Debug, Deserialize)]
67pub(crate) struct PurchaseResultPayload {
68 kind: String,
69 #[serde(rename = "verificationResult")]
70 verification_result: Option<VerificationResultPayload<TransactionPayload>>,
71}
72
73impl PurchaseResultPayload {
74 pub(crate) fn into_purchase_result(
75 self,
76 transaction_handle: *mut core::ffi::c_void,
77 ) -> Result<PurchaseResult, StoreKitError> {
78 match self.kind.as_str() {
79 "success" => {
80 let verification_result = self.verification_result.ok_or_else(|| {
81 StoreKitError::Unknown(
82 "StoreKit reported a successful purchase without a verification result"
83 .to_owned(),
84 )
85 })?;
86 let transaction = verification_result.into_result(|payload| {
87 Transaction::from_raw_parts(transaction_handle, payload)
88 })?;
89 Ok(PurchaseResult::Success(transaction))
90 }
91 "userCancelled" => {
92 if !transaction_handle.is_null() {
93 unsafe { crate::ffi::sk_transaction_release(transaction_handle) };
94 }
95 Ok(PurchaseResult::UserCancelled)
96 }
97 "pending" => {
98 if !transaction_handle.is_null() {
99 unsafe { crate::ffi::sk_transaction_release(transaction_handle) };
100 }
101 Ok(PurchaseResult::Pending)
102 }
103 other => {
104 if !transaction_handle.is_null() {
105 unsafe { crate::ffi::sk_transaction_release(transaction_handle) };
106 }
107 Err(StoreKitError::Unknown(format!(
108 "StoreKit returned an unknown purchase result kind '{other}'"
109 )))
110 }
111 }
112 }
113}