diff --git a/FeatureProbe.podspec b/FeatureProbe.podspec
new file mode 100644
index 0000000..588ddf5
--- /dev/null
+++ b/FeatureProbe.podspec
@@ -0,0 +1,15 @@
+Pod::Spec.new do |s|
+ s.name = 'FeatureProbe'
+ s.version = '1.0.1'
+ s.license = { :type => 'MIT' }
+ s.homepage = 'https://www.featureprobe.com/'
+ s.summary = 'iOS feature probe SDK'
+ s.source = { :git => 'git@github.com:FeatureProbe/client-sdk-ios.git', :tag => s.version }
+ s.source_files = 'Sources/**/*.swift'
+ s.authors = 'FeatreProbeTeam'
+
+ s.platform = :ios, '9.0'
+ s.pod_target_xcconfig = { 'VALID_ARCHS' => 'x86_64 arm64' }
+ s.swift_versions = ['4.0', '4.2', '5.0', '5.5']
+ s.vendored_frameworks = "FeatureProbeFFI.xcframework"
+ end
diff --git a/FeatureProbeFFI.xcframework/Info.plist b/FeatureProbeFFI.xcframework/Info.plist
new file mode 100644
index 0000000..f679b19
--- /dev/null
+++ b/FeatureProbeFFI.xcframework/Info.plist
@@ -0,0 +1,40 @@
+
+
+
+
+ AvailableLibraries
+
+
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ FeatureProbeFFI.framework
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ LibraryIdentifier
+ ios-arm64_x86_64-simulator
+ LibraryPath
+ FeatureProbeFFI.framework
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/FeatureProbeFFI b/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/FeatureProbeFFI
new file mode 100644
index 0000000..afcd14d
Binary files /dev/null and b/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/FeatureProbeFFI differ
diff --git a/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.h b/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.h
new file mode 100644
index 0000000..cc160df
--- /dev/null
+++ b/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.h
@@ -0,0 +1,140 @@
+// This file was autogenerated by some hot garbage in the `uniffi` crate.
+// Trust me, you don't want to mess with it!
+
+#pragma once
+
+#include
+#include
+
+// The following structs are used to implement the lowest level
+// of the FFI, and thus useful to multiple uniffied crates.
+// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H.
+#ifdef UNIFFI_SHARED_H
+ // We also try to prevent mixing versions of shared uniffi header structs.
+ // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4
+ #ifndef UNIFFI_SHARED_HEADER_V4
+ #error Combining helper code from multiple versions of uniffi is not supported
+ #endif // ndef UNIFFI_SHARED_HEADER_V4
+#else
+#define UNIFFI_SHARED_H
+#define UNIFFI_SHARED_HEADER_V4
+// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
+// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️
+
+typedef struct RustBuffer
+{
+ int32_t capacity;
+ int32_t len;
+ uint8_t *_Nullable data;
+} RustBuffer;
+
+typedef int32_t (*ForeignCallback)(uint64_t, int32_t, RustBuffer, RustBuffer *_Nonnull);
+
+typedef struct ForeignBytes
+{
+ int32_t len;
+ const uint8_t *_Nullable data;
+} ForeignBytes;
+
+// Error definitions
+typedef struct RustCallStatus {
+ int8_t code;
+ RustBuffer errorBuf;
+} RustCallStatus;
+
+// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
+// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️
+#endif // def UNIFFI_SHARED_H
+
+void ffi_featureprobe_17ce_FeatureProbe_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void*_Nonnull featureprobe_17ce_FeatureProbe_new(
+ void*_Nonnull config,void*_Nonnull user,
+ RustCallStatus *_Nonnull out_status
+ );
+int8_t featureprobe_17ce_FeatureProbe_bool_value(
+ void*_Nonnull ptr,RustBuffer key,int8_t default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_bool_detail(
+ void*_Nonnull ptr,RustBuffer key,int8_t default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+double featureprobe_17ce_FeatureProbe_number_value(
+ void*_Nonnull ptr,RustBuffer key,double default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_number_detail(
+ void*_Nonnull ptr,RustBuffer key,double default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_string_value(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_string_detail(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_json_value(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_json_detail(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_FPUser_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void*_Nonnull featureprobe_17ce_FPUser_new(
+ RustBuffer key,
+ RustCallStatus *_Nonnull out_status
+ );
+void featureprobe_17ce_FPUser_set_attr(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer value,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_FPUrl_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_FPUrlBuilder_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void*_Nonnull featureprobe_17ce_FPUrlBuilder_new(
+ RustBuffer remote_url,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FPUrlBuilder_build(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_FPConfig_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void*_Nonnull featureprobe_17ce_FPConfig_new(
+ void*_Nonnull remote_url,RustBuffer client_sdk_key,uint8_t refresh_interval,int8_t wait_first_resp,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer ffi_featureprobe_17ce_rustbuffer_alloc(
+ int32_t size,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer ffi_featureprobe_17ce_rustbuffer_from_bytes(
+ ForeignBytes bytes,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_rustbuffer_free(
+ RustBuffer buf,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer ffi_featureprobe_17ce_rustbuffer_reserve(
+ RustBuffer buf,int32_t additional,
+ RustCallStatus *_Nonnull out_status
+ );
diff --git a/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.modulemap b/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.modulemap
new file mode 100644
index 0000000..7423a34
--- /dev/null
+++ b/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.modulemap
@@ -0,0 +1,6 @@
+// This file was autogenerated by some hot garbage in the `uniffi` crate.
+// Trust me, you don't want to mess with it!
+module FeatureProbeFFI {
+ header "FeatureProbeFFI.h"
+ export *
+}
\ No newline at end of file
diff --git a/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Modules/module.modulemap b/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Modules/module.modulemap
new file mode 100644
index 0000000..7eeb8cb
--- /dev/null
+++ b/FeatureProbeFFI.xcframework/ios-arm64/FeatureProbeFFI.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module FeatureProbeFFI {
+ umbrella header "FeatureprobeFFI.h"
+
+ export *
+ module * { export * }
+}
diff --git a/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/FeatureProbeFFI b/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/FeatureProbeFFI
new file mode 100644
index 0000000..c4d36bd
Binary files /dev/null and b/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/FeatureProbeFFI differ
diff --git a/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.h b/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.h
new file mode 100644
index 0000000..cc160df
--- /dev/null
+++ b/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.h
@@ -0,0 +1,140 @@
+// This file was autogenerated by some hot garbage in the `uniffi` crate.
+// Trust me, you don't want to mess with it!
+
+#pragma once
+
+#include
+#include
+
+// The following structs are used to implement the lowest level
+// of the FFI, and thus useful to multiple uniffied crates.
+// We ensure they are declared exactly once, with a header guard, UNIFFI_SHARED_H.
+#ifdef UNIFFI_SHARED_H
+ // We also try to prevent mixing versions of shared uniffi header structs.
+ // If you add anything to the #else block, you must increment the version suffix in UNIFFI_SHARED_HEADER_V4
+ #ifndef UNIFFI_SHARED_HEADER_V4
+ #error Combining helper code from multiple versions of uniffi is not supported
+ #endif // ndef UNIFFI_SHARED_HEADER_V4
+#else
+#define UNIFFI_SHARED_H
+#define UNIFFI_SHARED_HEADER_V4
+// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
+// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️
+
+typedef struct RustBuffer
+{
+ int32_t capacity;
+ int32_t len;
+ uint8_t *_Nullable data;
+} RustBuffer;
+
+typedef int32_t (*ForeignCallback)(uint64_t, int32_t, RustBuffer, RustBuffer *_Nonnull);
+
+typedef struct ForeignBytes
+{
+ int32_t len;
+ const uint8_t *_Nullable data;
+} ForeignBytes;
+
+// Error definitions
+typedef struct RustCallStatus {
+ int8_t code;
+ RustBuffer errorBuf;
+} RustCallStatus;
+
+// ⚠️ Attention: If you change this #else block (ending in `#endif // def UNIFFI_SHARED_H`) you *must* ⚠️
+// ⚠️ increment the version suffix in all instances of UNIFFI_SHARED_HEADER_V4 in this file. ⚠️
+#endif // def UNIFFI_SHARED_H
+
+void ffi_featureprobe_17ce_FeatureProbe_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void*_Nonnull featureprobe_17ce_FeatureProbe_new(
+ void*_Nonnull config,void*_Nonnull user,
+ RustCallStatus *_Nonnull out_status
+ );
+int8_t featureprobe_17ce_FeatureProbe_bool_value(
+ void*_Nonnull ptr,RustBuffer key,int8_t default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_bool_detail(
+ void*_Nonnull ptr,RustBuffer key,int8_t default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+double featureprobe_17ce_FeatureProbe_number_value(
+ void*_Nonnull ptr,RustBuffer key,double default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_number_detail(
+ void*_Nonnull ptr,RustBuffer key,double default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_string_value(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_string_detail(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_json_value(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FeatureProbe_json_detail(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer default_value,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_FPUser_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void*_Nonnull featureprobe_17ce_FPUser_new(
+ RustBuffer key,
+ RustCallStatus *_Nonnull out_status
+ );
+void featureprobe_17ce_FPUser_set_attr(
+ void*_Nonnull ptr,RustBuffer key,RustBuffer value,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_FPUrl_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_FPUrlBuilder_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void*_Nonnull featureprobe_17ce_FPUrlBuilder_new(
+ RustBuffer remote_url,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer featureprobe_17ce_FPUrlBuilder_build(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_FPConfig_object_free(
+ void*_Nonnull ptr,
+ RustCallStatus *_Nonnull out_status
+ );
+void*_Nonnull featureprobe_17ce_FPConfig_new(
+ void*_Nonnull remote_url,RustBuffer client_sdk_key,uint8_t refresh_interval,int8_t wait_first_resp,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer ffi_featureprobe_17ce_rustbuffer_alloc(
+ int32_t size,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer ffi_featureprobe_17ce_rustbuffer_from_bytes(
+ ForeignBytes bytes,
+ RustCallStatus *_Nonnull out_status
+ );
+void ffi_featureprobe_17ce_rustbuffer_free(
+ RustBuffer buf,
+ RustCallStatus *_Nonnull out_status
+ );
+RustBuffer ffi_featureprobe_17ce_rustbuffer_reserve(
+ RustBuffer buf,int32_t additional,
+ RustCallStatus *_Nonnull out_status
+ );
diff --git a/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.modulemap b/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.modulemap
new file mode 100644
index 0000000..7423a34
--- /dev/null
+++ b/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Headers/FeatureProbeFFI.modulemap
@@ -0,0 +1,6 @@
+// This file was autogenerated by some hot garbage in the `uniffi` crate.
+// Trust me, you don't want to mess with it!
+module FeatureProbeFFI {
+ header "FeatureProbeFFI.h"
+ export *
+}
\ No newline at end of file
diff --git a/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Modules/module.modulemap b/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Modules/module.modulemap
new file mode 100644
index 0000000..7eeb8cb
--- /dev/null
+++ b/FeatureProbeFFI.xcframework/ios-arm64_x86_64-simulator/FeatureProbeFFI.framework/Modules/module.modulemap
@@ -0,0 +1,6 @@
+framework module FeatureProbeFFI {
+ umbrella header "FeatureprobeFFI.h"
+
+ export *
+ module * { export * }
+}
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..12276b7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2022 FeatureProbe
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/Package.swift b/Package.swift
new file mode 100644
index 0000000..d8bf277
--- /dev/null
+++ b/Package.swift
@@ -0,0 +1,27 @@
+// swift-tools-version: 5.4
+import PackageDescription
+
+let package = Package(
+ name: "FeatureProbe",
+ platforms: [.iOS(.v9)],
+ products: [
+ // Products define the executables and libraries a package produces, and make them visible to other packages.
+ .library(
+ name: "FeatureProbe",
+ targets: ["FeatureProbe"]),
+ ],
+ dependencies: [
+ ],
+ targets: [
+ // Targets are the basic building blocks of a package. A target can define a module or a test suite.
+ // Targets can depend on other targets in this package, and on products in packages this package depends on.
+ .binaryTarget(
+ name: "FeatureProbeFFI",
+ path: "./FeatureProbeFFI.xcframework"
+ ),
+ .target(
+ name: "FeatureProbe",
+ dependencies: ["FeatureProbeFFI"]
+ )
+ ]
+)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..034fc06
--- /dev/null
+++ b/README.md
@@ -0,0 +1,78 @@
+# FeatureProbe iOS-SDK
+
+## Usage
+
+Currently support two kinds of package manager:
+
+1. Swift Package Manager
+ XCode -> File -> Add Packages -> input `https://github.com/FeatureProbe/client-sdk-ios.git`
+
+2. Cocoapods
+ add `pod 'FeatureProbe', :git => 'git@github.com:FeatureProbe/client-sdk-ios.git'` to Podfile
+ `pod install` or `pod update`
+
+```swift
+import FeatureProbe
+
+let url = FpUrlBuilder(remoteUrl: "remote_url").build();
+let user = FpUser(key: "key123")
+user.setAttr(key: "city", value: "1")
+let config = FpConfig(
+ remoteUrl: url!,
+ clientSdkKey: "client-9d885a68ca2955dfb3a7c95435c0c4faad70b50d",
+ refreshInterval: 10,
+ waitFirstResp: true
+)
+let fp = FeatureProbe(config: config, user: user)
+let toggleValue = fp.stringDetail(key: "ab_test", defaultValue: "red")
+print("toogle value is \(toggleValue)")
+
+```
+
+```objective-c
+#import "FeatureProbe-Swift.h"
+
+NSString *urlStr = @"remote_url";
+FpUrl *url = [[[FpUrlBuilder alloc] initWithRemoteUrl: urlStr] build];
+FpUser *user = [[FpUser alloc] initWithKey:@"user_key"];
+FpConfig *config = [[FpConfig alloc] initWithRemoteUrl: url clientSdkKey:@"client-9d885a68ca2955dfb3a7c95435c0c4faad70b50d" refreshInterval: 10 waitFirstResp: true];
+
+FeatureProbe *fp = [[FeatureProbe alloc] initWithConfig:config user:user];
+NSString *value = [fp stringValueWithKey:@"ab_test" defaultValue:@"red"];
+NSLog(@"value is %@", value);
+
+```
+
+## Build
+build from repo: `git@github.com:FeatureProbe/client-sdk-mobile.git`
+
+1. install uniffi codegen tool
+
+cargo install uniffi_bindgen
+
+2. install rust android target
+
+rustup target add aarch64-apple-ios
+rustup target add aarch64-apple-ios-sim
+rustup target add x86_64-apple-ios
+
+3. build xcframework
+
+`./build-xcframework.sh`
+
+4. push to git
+
+```
+cd client-sdk-ios
+git commit -m 'xxx'
+git push origin master
+```
+
+
+## Contributing
+We are working on continue evolving FeatureProbe core, making it flexible and easier to use.
+Development of FeatureProbe happens in the open on GitHub, and we are grateful to the
+community for contributing bugfixes and improvements.
+
+Please read [CONTRIBUTING](https://github.com/FeatureProbe/featureprobe/blob/master/CONTRIBUTING.md)
+for details on our code of conduct, and the process for taking part in improving FeatureProbe.
diff --git a/Sources/FeatureProbe/FeatureProbe.swift b/Sources/FeatureProbe/FeatureProbe.swift
new file mode 100644
index 0000000..f52c0a6
--- /dev/null
+++ b/Sources/FeatureProbe/FeatureProbe.swift
@@ -0,0 +1,1161 @@
+// This file was autogenerated by some hot garbage in the `uniffi` crate.
+// Trust me, you don't want to mess with it!
+import Foundation
+
+// Depending on the consumer's build setup, the low-level FFI code
+// might be in a separate module, or it might be compiled inline into
+// this module. This is a bit of light hackery to work with both.
+#if canImport(FeatureProbeFFI)
+import FeatureProbeFFI
+#endif
+
+fileprivate extension RustBuffer {
+ // Allocate a new buffer, copying the contents of a `UInt8` array.
+ init(bytes: [UInt8]) {
+ let rbuf = bytes.withUnsafeBufferPointer { ptr in
+ RustBuffer.from(ptr)
+ }
+ self.init(capacity: rbuf.capacity, len: rbuf.len, data: rbuf.data)
+ }
+
+ static func from(_ ptr: UnsafeBufferPointer) -> RustBuffer {
+ try! rustCall { ffi_featureprobe_17ce_rustbuffer_from_bytes(ForeignBytes(bufferPointer: ptr), $0) }
+ }
+
+ // Frees the buffer in place.
+ // The buffer must not be used after this is called.
+ func deallocate() {
+ try! rustCall { ffi_featureprobe_17ce_rustbuffer_free(self, $0) }
+ }
+}
+
+fileprivate extension ForeignBytes {
+ init(bufferPointer: UnsafeBufferPointer) {
+ self.init(len: Int32(bufferPointer.count), data: bufferPointer.baseAddress)
+ }
+}
+
+// For every type used in the interface, we provide helper methods for conveniently
+// lifting and lowering that type from C-compatible data, and for reading and writing
+// values of that type in a buffer.
+
+// Helper classes/extensions that don't change.
+// Someday, this will be in a libray of its own.
+
+fileprivate extension Data {
+ init(rustBuffer: RustBuffer) {
+ // TODO: This copies the buffer. Can we read directly from a
+ // Rust buffer?
+ self.init(bytes: rustBuffer.data!, count: Int(rustBuffer.len))
+ }
+}
+
+// A helper class to read values out of a byte buffer.
+fileprivate class Reader {
+ let data: Data
+ var offset: Data.Index
+
+ init(data: Data) {
+ self.data = data
+ self.offset = 0
+ }
+
+ // Reads an integer at the current offset, in big-endian order, and advances
+ // the offset on success. Throws if reading the integer would move the
+ // offset past the end of the buffer.
+ func readInt() throws -> T {
+ let range = offset...size
+ guard data.count >= range.upperBound else {
+ throw UniffiInternalError.bufferOverflow
+ }
+ if T.self == UInt8.self {
+ let value = data[offset]
+ offset += 1
+ return value as! T
+ }
+ var value: T = 0
+ let _ = withUnsafeMutableBytes(of: &value, { data.copyBytes(to: $0, from: range)})
+ offset = range.upperBound
+ return value.bigEndian
+ }
+
+ // Reads an arbitrary number of bytes, to be used to read
+ // raw bytes, this is useful when lifting strings
+ func readBytes(count: Int) throws -> Array {
+ let range = offset..<(offset+count)
+ guard data.count >= range.upperBound else {
+ throw UniffiInternalError.bufferOverflow
+ }
+ var value = [UInt8](repeating: 0, count: count)
+ value.withUnsafeMutableBufferPointer({ buffer in
+ data.copyBytes(to: buffer, from: range)
+ })
+ offset = range.upperBound
+ return value
+ }
+
+ // Reads a float at the current offset.
+ @inlinable
+ func readFloat() throws -> Float {
+ return Float(bitPattern: try readInt())
+ }
+
+ // Reads a float at the current offset.
+ @inlinable
+ func readDouble() throws -> Double {
+ return Double(bitPattern: try readInt())
+ }
+
+ // Indicates if the offset has reached the end of the buffer.
+ @inlinable
+ func hasRemaining() -> Bool {
+ return offset < data.count
+ }
+}
+
+// A helper class to write values into a byte buffer.
+fileprivate class Writer {
+ var bytes: [UInt8]
+ var offset: Array.Index
+
+ init() {
+ self.bytes = []
+ self.offset = 0
+ }
+
+ func writeBytes(_ byteArr: S) where S: Sequence, S.Element == UInt8 {
+ bytes.append(contentsOf: byteArr)
+ }
+
+ // Writes an integer in big-endian order.
+ //
+ // Warning: make sure what you are trying to write
+ // is in the correct type!
+ func writeInt(_ value: T) {
+ var value = value.bigEndian
+ withUnsafeBytes(of: &value) { bytes.append(contentsOf: $0) }
+ }
+
+ @inlinable
+ func writeFloat(_ value: Float) {
+ writeInt(value.bitPattern)
+ }
+
+ @inlinable
+ func writeDouble(_ value: Double) {
+ writeInt(value.bitPattern)
+ }
+}
+
+// Protocol for types that transfer other types across the FFI. This is
+// analogous go the Rust trait of the same name.
+fileprivate protocol FfiConverter {
+ associatedtype FfiType
+ associatedtype SwiftType
+
+ static func lift(_ value: FfiType) throws -> SwiftType
+ static func lower(_ value: SwiftType) -> FfiType
+ static func read(from buf: Reader) throws -> SwiftType
+ static func write(_ value: SwiftType, into buf: Writer)
+}
+
+// Types conforming to `Primitive` pass themselves directly over the FFI.
+fileprivate protocol FfiConverterPrimitive: FfiConverter where FfiType == SwiftType { }
+
+extension FfiConverterPrimitive {
+ static func lift(_ value: FfiType) throws -> SwiftType {
+ return value
+ }
+
+ static func lower(_ value: SwiftType) -> FfiType {
+ return value
+ }
+}
+
+// Types conforming to `FfiConverterRustBuffer` lift and lower into a `RustBuffer`.
+// Used for complex types where it's hard to write a custom lift/lower.
+fileprivate protocol FfiConverterRustBuffer: FfiConverter where FfiType == RustBuffer {}
+
+extension FfiConverterRustBuffer {
+ static func lift(_ buf: RustBuffer) throws -> SwiftType {
+ let reader = Reader(data: Data(rustBuffer: buf))
+ let value = try read(from: reader)
+ if reader.hasRemaining() {
+ throw UniffiInternalError.incompleteData
+ }
+ buf.deallocate()
+ return value
+ }
+
+ static func lower(_ value: SwiftType) -> RustBuffer {
+ let writer = Writer()
+ write(value, into: writer)
+ return RustBuffer(bytes: writer.bytes)
+ }
+}
+// An error type for FFI errors. These errors occur at the UniFFI level, not
+// the library level.
+fileprivate enum UniffiInternalError: LocalizedError {
+ case bufferOverflow
+ case incompleteData
+ case unexpectedOptionalTag
+ case unexpectedEnumCase
+ case unexpectedNullPointer
+ case unexpectedRustCallStatusCode
+ case unexpectedRustCallError
+ case unexpectedStaleHandle
+ case rustPanic(_ message: String)
+
+ public var errorDescription: String? {
+ switch self {
+ case .bufferOverflow: return "Reading the requested value would read past the end of the buffer"
+ case .incompleteData: return "The buffer still has data after lifting its containing value"
+ case .unexpectedOptionalTag: return "Unexpected optional tag; should be 0 or 1"
+ case .unexpectedEnumCase: return "Raw enum value doesn't match any cases"
+ case .unexpectedNullPointer: return "Raw pointer value was null"
+ case .unexpectedRustCallStatusCode: return "Unexpected RustCallStatus code"
+ case .unexpectedRustCallError: return "CALL_ERROR but no errorClass specified"
+ case .unexpectedStaleHandle: return "The object in the handle map has been dropped already"
+ case let .rustPanic(message): return message
+ }
+ }
+}
+
+fileprivate let CALL_SUCCESS: Int8 = 0
+fileprivate let CALL_ERROR: Int8 = 1
+fileprivate let CALL_PANIC: Int8 = 2
+
+fileprivate extension RustCallStatus {
+ init() {
+ self.init(
+ code: CALL_SUCCESS,
+ errorBuf: RustBuffer.init(
+ capacity: 0,
+ len: 0,
+ data: nil
+ )
+ )
+ }
+}
+
+private func rustCall(_ callback: (UnsafeMutablePointer) -> T) throws -> T {
+ try makeRustCall(callback, errorHandler: {
+ $0.deallocate()
+ return UniffiInternalError.unexpectedRustCallError
+ })
+}
+
+private func rustCallWithError
+ (_ errorFfiConverter: F.Type, _ callback: (UnsafeMutablePointer) -> T) throws -> T
+ where F.SwiftType: Error, F.FfiType == RustBuffer
+ {
+ try makeRustCall(callback, errorHandler: { return try errorFfiConverter.lift($0) })
+}
+
+private func makeRustCall(_ callback: (UnsafeMutablePointer) -> T, errorHandler: (RustBuffer) throws -> Error) throws -> T {
+ var callStatus = RustCallStatus.init()
+ let returnedVal = callback(&callStatus)
+ switch callStatus.code {
+ case CALL_SUCCESS:
+ return returnedVal
+
+ case CALL_ERROR:
+ throw try errorHandler(callStatus.errorBuf)
+
+ case CALL_PANIC:
+ // When the rust code sees a panic, it tries to construct a RustBuffer
+ // with the message. But if that code panics, then it just sends back
+ // an empty buffer.
+ if callStatus.errorBuf.len > 0 {
+ throw UniffiInternalError.rustPanic(try FfiConverterString.lift(callStatus.errorBuf))
+ } else {
+ callStatus.errorBuf.deallocate()
+ throw UniffiInternalError.rustPanic("Rust panic")
+ }
+
+ default:
+ throw UniffiInternalError.unexpectedRustCallStatusCode
+ }
+}
+
+// Public interface members begin here.
+
+
+public protocol FeatureProbeProtocol {
+ func boolValue(key: String, defaultValue: Bool) -> Bool
+ func boolDetail(key: String, defaultValue: Bool) -> FpBoolDetail
+ func numberValue(key: String, defaultValue: Double) -> Double
+ func numberDetail(key: String, defaultValue: Double) -> FpNumDetail
+ func stringValue(key: String, defaultValue: String) -> String
+ func stringDetail(key: String, defaultValue: String) -> FpStrDetail
+ func jsonValue(key: String, defaultValue: String) -> String
+ func jsonDetail(key: String, defaultValue: String) -> FpJsonDetail
+
+}
+
+public class FeatureProbe: FeatureProbeProtocol {
+ fileprivate let pointer: UnsafeMutableRawPointer
+
+ // TODO: We'd like this to be `private` but for Swifty reasons,
+ // we can't implement `FfiConverter` without making this `required` and we can't
+ // make it `required` without making it `public`.
+ required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
+ self.pointer = pointer
+ }
+ public convenience init(config: FpConfig, user: FpUser) {
+ self.init(unsafeFromRawPointer: try!
+
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_new(
+ FfiConverterTypeFpConfig.lower(config),
+ FfiConverterTypeFpUser.lower(user), $0)
+})
+ }
+
+ deinit {
+ try! rustCall { ffi_featureprobe_17ce_FeatureProbe_object_free(pointer, $0) }
+ }
+
+
+
+
+ public func boolValue(key: String, defaultValue: Bool) -> Bool {
+ return try! FfiConverterBool.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_bool_value(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterBool.lower(defaultValue), $0
+ )
+}
+ )
+ }
+ public func boolDetail(key: String, defaultValue: Bool) -> FpBoolDetail {
+ return try! FfiConverterTypeFpBoolDetail.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_bool_detail(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterBool.lower(defaultValue), $0
+ )
+}
+ )
+ }
+ public func numberValue(key: String, defaultValue: Double) -> Double {
+ return try! FfiConverterDouble.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_number_value(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterDouble.lower(defaultValue), $0
+ )
+}
+ )
+ }
+ public func numberDetail(key: String, defaultValue: Double) -> FpNumDetail {
+ return try! FfiConverterTypeFpNumDetail.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_number_detail(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterDouble.lower(defaultValue), $0
+ )
+}
+ )
+ }
+ public func stringValue(key: String, defaultValue: String) -> String {
+ return try! FfiConverterString.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_string_value(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterString.lower(defaultValue), $0
+ )
+}
+ )
+ }
+ public func stringDetail(key: String, defaultValue: String) -> FpStrDetail {
+ return try! FfiConverterTypeFpStrDetail.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_string_detail(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterString.lower(defaultValue), $0
+ )
+}
+ )
+ }
+ public func jsonValue(key: String, defaultValue: String) -> String {
+ return try! FfiConverterString.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_json_value(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterString.lower(defaultValue), $0
+ )
+}
+ )
+ }
+ public func jsonDetail(key: String, defaultValue: String) -> FpJsonDetail {
+ return try! FfiConverterTypeFpJsonDetail.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FeatureProbe_json_detail(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterString.lower(defaultValue), $0
+ )
+}
+ )
+ }
+
+}
+
+
+fileprivate struct FfiConverterTypeFeatureProbe: FfiConverter {
+ typealias FfiType = UnsafeMutableRawPointer
+ typealias SwiftType = FeatureProbe
+
+ static func read(from buf: Reader) throws -> FeatureProbe {
+ let v: UInt64 = try buf.readInt()
+ // The Rust code won't compile if a pointer won't fit in a UInt64.
+ // We have to go via `UInt` because that's the thing that's the size of a pointer.
+ let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
+ if (ptr == nil) {
+ throw UniffiInternalError.unexpectedNullPointer
+ }
+ return try lift(ptr!)
+ }
+
+ static func write(_ value: FeatureProbe, into buf: Writer) {
+ // This fiddling is because `Int` is the thing that's the same size as a pointer.
+ // The Rust code won't compile if a pointer won't fit in a `UInt64`.
+ buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value)))))
+ }
+
+ static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FeatureProbe {
+ return FeatureProbe(unsafeFromRawPointer: pointer)
+ }
+
+ static func lower(_ value: FeatureProbe) -> UnsafeMutableRawPointer {
+ return value.pointer
+ }
+}
+
+public protocol FPUserProtocol {
+ func setAttr(key: String, value: String)
+
+}
+
+public class FpUser: FPUserProtocol {
+ fileprivate let pointer: UnsafeMutableRawPointer
+
+ // TODO: We'd like this to be `private` but for Swifty reasons,
+ // we can't implement `FfiConverter` without making this `required` and we can't
+ // make it `required` without making it `public`.
+ required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
+ self.pointer = pointer
+ }
+ public convenience init(key: String) {
+ self.init(unsafeFromRawPointer: try!
+
+ rustCall() {
+
+ featureprobe_17ce_FPUser_new(
+ FfiConverterString.lower(key), $0)
+})
+ }
+
+ deinit {
+ try! rustCall { ffi_featureprobe_17ce_FPUser_object_free(pointer, $0) }
+ }
+
+
+
+
+ public func setAttr(key: String, value: String) {
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FPUser_set_attr(self.pointer,
+ FfiConverterString.lower(key),
+ FfiConverterString.lower(value), $0
+ )
+}
+ }
+
+}
+
+
+fileprivate struct FfiConverterTypeFpUser: FfiConverter {
+ typealias FfiType = UnsafeMutableRawPointer
+ typealias SwiftType = FpUser
+
+ static func read(from buf: Reader) throws -> FpUser {
+ let v: UInt64 = try buf.readInt()
+ // The Rust code won't compile if a pointer won't fit in a UInt64.
+ // We have to go via `UInt` because that's the thing that's the size of a pointer.
+ let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
+ if (ptr == nil) {
+ throw UniffiInternalError.unexpectedNullPointer
+ }
+ return try lift(ptr!)
+ }
+
+ static func write(_ value: FpUser, into buf: Writer) {
+ // This fiddling is because `Int` is the thing that's the same size as a pointer.
+ // The Rust code won't compile if a pointer won't fit in a `UInt64`.
+ buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value)))))
+ }
+
+ static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FpUser {
+ return FpUser(unsafeFromRawPointer: pointer)
+ }
+
+ static func lower(_ value: FpUser) -> UnsafeMutableRawPointer {
+ return value.pointer
+ }
+}
+
+public protocol FPUrlProtocol {
+
+}
+
+public class FpUrl: FPUrlProtocol {
+ fileprivate let pointer: UnsafeMutableRawPointer
+
+ // TODO: We'd like this to be `private` but for Swifty reasons,
+ // we can't implement `FfiConverter` without making this `required` and we can't
+ // make it `required` without making it `public`.
+ required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
+ self.pointer = pointer
+ }
+
+ deinit {
+ try! rustCall { ffi_featureprobe_17ce_FPUrl_object_free(pointer, $0) }
+ }
+
+
+
+
+
+}
+
+
+fileprivate struct FfiConverterTypeFpUrl: FfiConverter {
+ typealias FfiType = UnsafeMutableRawPointer
+ typealias SwiftType = FpUrl
+
+ static func read(from buf: Reader) throws -> FpUrl {
+ let v: UInt64 = try buf.readInt()
+ // The Rust code won't compile if a pointer won't fit in a UInt64.
+ // We have to go via `UInt` because that's the thing that's the size of a pointer.
+ let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
+ if (ptr == nil) {
+ throw UniffiInternalError.unexpectedNullPointer
+ }
+ return try lift(ptr!)
+ }
+
+ static func write(_ value: FpUrl, into buf: Writer) {
+ // This fiddling is because `Int` is the thing that's the same size as a pointer.
+ // The Rust code won't compile if a pointer won't fit in a `UInt64`.
+ buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value)))))
+ }
+
+ static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FpUrl {
+ return FpUrl(unsafeFromRawPointer: pointer)
+ }
+
+ static func lower(_ value: FpUrl) -> UnsafeMutableRawPointer {
+ return value.pointer
+ }
+}
+
+public protocol FPUrlBuilderProtocol {
+ func build() -> FpUrl?
+
+}
+
+public class FpUrlBuilder: FPUrlBuilderProtocol {
+ fileprivate let pointer: UnsafeMutableRawPointer
+
+ // TODO: We'd like this to be `private` but for Swifty reasons,
+ // we can't implement `FfiConverter` without making this `required` and we can't
+ // make it `required` without making it `public`.
+ required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
+ self.pointer = pointer
+ }
+ public convenience init(remoteUrl: String) {
+ self.init(unsafeFromRawPointer: try!
+
+ rustCall() {
+
+ featureprobe_17ce_FPUrlBuilder_new(
+ FfiConverterString.lower(remoteUrl), $0)
+})
+ }
+
+ deinit {
+ try! rustCall { ffi_featureprobe_17ce_FPUrlBuilder_object_free(pointer, $0) }
+ }
+
+
+
+
+ public func build() -> FpUrl? {
+ return try! FfiConverterOptionTypeFpUrl.lift(
+ try!
+ rustCall() {
+
+ featureprobe_17ce_FPUrlBuilder_build(self.pointer, $0
+ )
+}
+ )
+ }
+
+}
+
+
+fileprivate struct FfiConverterTypeFpUrlBuilder: FfiConverter {
+ typealias FfiType = UnsafeMutableRawPointer
+ typealias SwiftType = FpUrlBuilder
+
+ static func read(from buf: Reader) throws -> FpUrlBuilder {
+ let v: UInt64 = try buf.readInt()
+ // The Rust code won't compile if a pointer won't fit in a UInt64.
+ // We have to go via `UInt` because that's the thing that's the size of a pointer.
+ let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
+ if (ptr == nil) {
+ throw UniffiInternalError.unexpectedNullPointer
+ }
+ return try lift(ptr!)
+ }
+
+ static func write(_ value: FpUrlBuilder, into buf: Writer) {
+ // This fiddling is because `Int` is the thing that's the same size as a pointer.
+ // The Rust code won't compile if a pointer won't fit in a `UInt64`.
+ buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value)))))
+ }
+
+ static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FpUrlBuilder {
+ return FpUrlBuilder(unsafeFromRawPointer: pointer)
+ }
+
+ static func lower(_ value: FpUrlBuilder) -> UnsafeMutableRawPointer {
+ return value.pointer
+ }
+}
+
+public protocol FPConfigProtocol {
+
+}
+
+public class FpConfig: FPConfigProtocol {
+ fileprivate let pointer: UnsafeMutableRawPointer
+
+ // TODO: We'd like this to be `private` but for Swifty reasons,
+ // we can't implement `FfiConverter` without making this `required` and we can't
+ // make it `required` without making it `public`.
+ required init(unsafeFromRawPointer pointer: UnsafeMutableRawPointer) {
+ self.pointer = pointer
+ }
+ public convenience init(remoteUrl: FpUrl, clientSdkKey: String, refreshInterval: UInt8, waitFirstResp: Bool) {
+ self.init(unsafeFromRawPointer: try!
+
+ rustCall() {
+
+ featureprobe_17ce_FPConfig_new(
+ FfiConverterTypeFpUrl.lower(remoteUrl),
+ FfiConverterString.lower(clientSdkKey),
+ FfiConverterUInt8.lower(refreshInterval),
+ FfiConverterBool.lower(waitFirstResp), $0)
+})
+ }
+
+ deinit {
+ try! rustCall { ffi_featureprobe_17ce_FPConfig_object_free(pointer, $0) }
+ }
+
+
+
+
+
+}
+
+
+fileprivate struct FfiConverterTypeFpConfig: FfiConverter {
+ typealias FfiType = UnsafeMutableRawPointer
+ typealias SwiftType = FpConfig
+
+ static func read(from buf: Reader) throws -> FpConfig {
+ let v: UInt64 = try buf.readInt()
+ // The Rust code won't compile if a pointer won't fit in a UInt64.
+ // We have to go via `UInt` because that's the thing that's the size of a pointer.
+ let ptr = UnsafeMutableRawPointer(bitPattern: UInt(truncatingIfNeeded: v))
+ if (ptr == nil) {
+ throw UniffiInternalError.unexpectedNullPointer
+ }
+ return try lift(ptr!)
+ }
+
+ static func write(_ value: FpConfig, into buf: Writer) {
+ // This fiddling is because `Int` is the thing that's the same size as a pointer.
+ // The Rust code won't compile if a pointer won't fit in a `UInt64`.
+ buf.writeInt(UInt64(bitPattern: Int64(Int(bitPattern: lower(value)))))
+ }
+
+ static func lift(_ pointer: UnsafeMutableRawPointer) throws -> FpConfig {
+ return FpConfig(unsafeFromRawPointer: pointer)
+ }
+
+ static func lower(_ value: FpConfig) -> UnsafeMutableRawPointer {
+ return value.pointer
+ }
+}
+
+public struct FpBoolDetail {
+ public var value: Bool
+ public var ruleIndex: UInt16?
+ public var version: UInt64?
+ public var reason: String
+
+ // Default memberwise initializers are never public by default, so we
+ // declare one manually.
+ public init(value: Bool, ruleIndex: UInt16?, version: UInt64?, reason: String) {
+ self.value = value
+ self.ruleIndex = ruleIndex
+ self.version = version
+ self.reason = reason
+ }
+}
+
+
+extension FpBoolDetail: Equatable, Hashable {
+ public static func ==(lhs: FpBoolDetail, rhs: FpBoolDetail) -> Bool {
+ if lhs.value != rhs.value {
+ return false
+ }
+ if lhs.ruleIndex != rhs.ruleIndex {
+ return false
+ }
+ if lhs.version != rhs.version {
+ return false
+ }
+ if lhs.reason != rhs.reason {
+ return false
+ }
+ return true
+ }
+
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(value)
+ hasher.combine(ruleIndex)
+ hasher.combine(version)
+ hasher.combine(reason)
+ }
+}
+
+
+fileprivate struct FfiConverterTypeFpBoolDetail: FfiConverterRustBuffer {
+ fileprivate static func read(from buf: Reader) throws -> FpBoolDetail {
+ return try FpBoolDetail(
+ value: FfiConverterBool.read(from: buf),
+ ruleIndex: FfiConverterOptionUInt16.read(from: buf),
+ version: FfiConverterOptionUInt64.read(from: buf),
+ reason: FfiConverterString.read(from: buf)
+ )
+ }
+
+ fileprivate static func write(_ value: FpBoolDetail, into buf: Writer) {
+ FfiConverterBool.write(value.value, into: buf)
+ FfiConverterOptionUInt16.write(value.ruleIndex, into: buf)
+ FfiConverterOptionUInt64.write(value.version, into: buf)
+ FfiConverterString.write(value.reason, into: buf)
+ }
+}
+
+public struct FpNumDetail {
+ public var value: Double
+ public var ruleIndex: UInt16?
+ public var version: UInt64?
+ public var reason: String
+
+ // Default memberwise initializers are never public by default, so we
+ // declare one manually.
+ public init(value: Double, ruleIndex: UInt16?, version: UInt64?, reason: String) {
+ self.value = value
+ self.ruleIndex = ruleIndex
+ self.version = version
+ self.reason = reason
+ }
+}
+
+
+extension FpNumDetail: Equatable, Hashable {
+ public static func ==(lhs: FpNumDetail, rhs: FpNumDetail) -> Bool {
+ if lhs.value != rhs.value {
+ return false
+ }
+ if lhs.ruleIndex != rhs.ruleIndex {
+ return false
+ }
+ if lhs.version != rhs.version {
+ return false
+ }
+ if lhs.reason != rhs.reason {
+ return false
+ }
+ return true
+ }
+
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(value)
+ hasher.combine(ruleIndex)
+ hasher.combine(version)
+ hasher.combine(reason)
+ }
+}
+
+
+fileprivate struct FfiConverterTypeFpNumDetail: FfiConverterRustBuffer {
+ fileprivate static func read(from buf: Reader) throws -> FpNumDetail {
+ return try FpNumDetail(
+ value: FfiConverterDouble.read(from: buf),
+ ruleIndex: FfiConverterOptionUInt16.read(from: buf),
+ version: FfiConverterOptionUInt64.read(from: buf),
+ reason: FfiConverterString.read(from: buf)
+ )
+ }
+
+ fileprivate static func write(_ value: FpNumDetail, into buf: Writer) {
+ FfiConverterDouble.write(value.value, into: buf)
+ FfiConverterOptionUInt16.write(value.ruleIndex, into: buf)
+ FfiConverterOptionUInt64.write(value.version, into: buf)
+ FfiConverterString.write(value.reason, into: buf)
+ }
+}
+
+public struct FpStrDetail {
+ public var value: String
+ public var ruleIndex: UInt16?
+ public var version: UInt64?
+ public var reason: String
+
+ // Default memberwise initializers are never public by default, so we
+ // declare one manually.
+ public init(value: String, ruleIndex: UInt16?, version: UInt64?, reason: String) {
+ self.value = value
+ self.ruleIndex = ruleIndex
+ self.version = version
+ self.reason = reason
+ }
+}
+
+
+extension FpStrDetail: Equatable, Hashable {
+ public static func ==(lhs: FpStrDetail, rhs: FpStrDetail) -> Bool {
+ if lhs.value != rhs.value {
+ return false
+ }
+ if lhs.ruleIndex != rhs.ruleIndex {
+ return false
+ }
+ if lhs.version != rhs.version {
+ return false
+ }
+ if lhs.reason != rhs.reason {
+ return false
+ }
+ return true
+ }
+
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(value)
+ hasher.combine(ruleIndex)
+ hasher.combine(version)
+ hasher.combine(reason)
+ }
+}
+
+
+fileprivate struct FfiConverterTypeFpStrDetail: FfiConverterRustBuffer {
+ fileprivate static func read(from buf: Reader) throws -> FpStrDetail {
+ return try FpStrDetail(
+ value: FfiConverterString.read(from: buf),
+ ruleIndex: FfiConverterOptionUInt16.read(from: buf),
+ version: FfiConverterOptionUInt64.read(from: buf),
+ reason: FfiConverterString.read(from: buf)
+ )
+ }
+
+ fileprivate static func write(_ value: FpStrDetail, into buf: Writer) {
+ FfiConverterString.write(value.value, into: buf)
+ FfiConverterOptionUInt16.write(value.ruleIndex, into: buf)
+ FfiConverterOptionUInt64.write(value.version, into: buf)
+ FfiConverterString.write(value.reason, into: buf)
+ }
+}
+
+public struct FpJsonDetail {
+ public var value: String
+ public var ruleIndex: UInt16?
+ public var version: UInt64?
+ public var reason: String
+
+ // Default memberwise initializers are never public by default, so we
+ // declare one manually.
+ public init(value: String, ruleIndex: UInt16?, version: UInt64?, reason: String) {
+ self.value = value
+ self.ruleIndex = ruleIndex
+ self.version = version
+ self.reason = reason
+ }
+}
+
+
+extension FpJsonDetail: Equatable, Hashable {
+ public static func ==(lhs: FpJsonDetail, rhs: FpJsonDetail) -> Bool {
+ if lhs.value != rhs.value {
+ return false
+ }
+ if lhs.ruleIndex != rhs.ruleIndex {
+ return false
+ }
+ if lhs.version != rhs.version {
+ return false
+ }
+ if lhs.reason != rhs.reason {
+ return false
+ }
+ return true
+ }
+
+ public func hash(into hasher: inout Hasher) {
+ hasher.combine(value)
+ hasher.combine(ruleIndex)
+ hasher.combine(version)
+ hasher.combine(reason)
+ }
+}
+
+
+fileprivate struct FfiConverterTypeFpJsonDetail: FfiConverterRustBuffer {
+ fileprivate static func read(from buf: Reader) throws -> FpJsonDetail {
+ return try FpJsonDetail(
+ value: FfiConverterString.read(from: buf),
+ ruleIndex: FfiConverterOptionUInt16.read(from: buf),
+ version: FfiConverterOptionUInt64.read(from: buf),
+ reason: FfiConverterString.read(from: buf)
+ )
+ }
+
+ fileprivate static func write(_ value: FpJsonDetail, into buf: Writer) {
+ FfiConverterString.write(value.value, into: buf)
+ FfiConverterOptionUInt16.write(value.ruleIndex, into: buf)
+ FfiConverterOptionUInt64.write(value.version, into: buf)
+ FfiConverterString.write(value.reason, into: buf)
+ }
+}
+fileprivate struct FfiConverterUInt8: FfiConverterPrimitive {
+ typealias FfiType = UInt8
+ typealias SwiftType = UInt8
+
+ static func read(from buf: Reader) throws -> UInt8 {
+ return try lift(buf.readInt())
+ }
+
+ static func write(_ value: UInt8, into buf: Writer) {
+ buf.writeInt(lower(value))
+ }
+}
+fileprivate struct FfiConverterUInt16: FfiConverterPrimitive {
+ typealias FfiType = UInt16
+ typealias SwiftType = UInt16
+
+ static func read(from buf: Reader) throws -> UInt16 {
+ return try lift(buf.readInt())
+ }
+
+ static func write(_ value: SwiftType, into buf: Writer) {
+ buf.writeInt(lower(value))
+ }
+}
+fileprivate struct FfiConverterUInt64: FfiConverterPrimitive {
+ typealias FfiType = UInt64
+ typealias SwiftType = UInt64
+
+ static func read(from buf: Reader) throws -> UInt64 {
+ return try lift(buf.readInt())
+ }
+
+ static func write(_ value: SwiftType, into buf: Writer) {
+ buf.writeInt(lower(value))
+ }
+}
+fileprivate struct FfiConverterDouble: FfiConverterPrimitive {
+ typealias FfiType = Double
+ typealias SwiftType = Double
+
+ static func read(from buf: Reader) throws -> Double {
+ return try lift(buf.readDouble())
+ }
+
+ static func write(_ value: Double, into buf: Writer) {
+ buf.writeDouble(lower(value))
+ }
+}
+fileprivate struct FfiConverterBool : FfiConverter {
+ typealias FfiType = Int8
+ typealias SwiftType = Bool
+
+ static func lift(_ value: Int8) throws -> Bool {
+ return value != 0
+ }
+
+ static func lower(_ value: Bool) -> Int8 {
+ return value ? 1 : 0
+ }
+
+ static func read(from buf: Reader) throws -> Bool {
+ return try lift(buf.readInt())
+ }
+
+ static func write(_ value: Bool, into buf: Writer) {
+ buf.writeInt(lower(value))
+ }
+}
+fileprivate struct FfiConverterString: FfiConverter {
+ typealias SwiftType = String
+ typealias FfiType = RustBuffer
+
+ static func lift(_ value: RustBuffer) throws -> String {
+ defer {
+ value.deallocate()
+ }
+ if value.data == nil {
+ return String()
+ }
+ let bytes = UnsafeBufferPointer(start: value.data!, count: Int(value.len))
+ return String(bytes: bytes, encoding: String.Encoding.utf8)!
+ }
+
+ static func lower(_ value: String) -> RustBuffer {
+ return value.utf8CString.withUnsafeBufferPointer { ptr in
+ // The swift string gives us int8_t, we want uint8_t.
+ ptr.withMemoryRebound(to: UInt8.self) { ptr in
+ // The swift string gives us a trailing null byte, we don't want it.
+ let buf = UnsafeBufferPointer(rebasing: ptr.prefix(upTo: ptr.count - 1))
+ return RustBuffer.from(buf)
+ }
+ }
+ }
+
+ static func read(from buf: Reader) throws -> String {
+ let len: Int32 = try buf.readInt()
+ return String(bytes: try buf.readBytes(count: Int(len)), encoding: String.Encoding.utf8)!
+ }
+
+ static func write(_ value: String, into buf: Writer) {
+ let len = Int32(value.utf8.count)
+ buf.writeInt(len)
+ buf.writeBytes(value.utf8)
+ }
+}
+// Helper code for FpConfig class is found in ObjectTemplate.swift
+// Helper code for FpUrl class is found in ObjectTemplate.swift
+// Helper code for FpUrlBuilder class is found in ObjectTemplate.swift
+// Helper code for FpUser class is found in ObjectTemplate.swift
+// Helper code for FeatureProbe class is found in ObjectTemplate.swift
+// Helper code for FpBoolDetail record is found in RecordTemplate.swift
+// Helper code for FpJsonDetail record is found in RecordTemplate.swift
+// Helper code for FpNumDetail record is found in RecordTemplate.swift
+// Helper code for FpStrDetail record is found in RecordTemplate.swift
+
+fileprivate struct FfiConverterOptionUInt16: FfiConverterRustBuffer {
+ typealias SwiftType = UInt16?
+
+ static func write(_ value: SwiftType, into buf: Writer) {
+ guard let value = value else {
+ buf.writeInt(Int8(0))
+ return
+ }
+ buf.writeInt(Int8(1))
+ FfiConverterUInt16.write(value, into: buf)
+ }
+
+ static func read(from buf: Reader) throws -> SwiftType {
+ switch try buf.readInt() as Int8 {
+ case 0: return nil
+ case 1: return try FfiConverterUInt16.read(from: buf)
+ default: throw UniffiInternalError.unexpectedOptionalTag
+ }
+ }
+}
+
+fileprivate struct FfiConverterOptionUInt64: FfiConverterRustBuffer {
+ typealias SwiftType = UInt64?
+
+ static func write(_ value: SwiftType, into buf: Writer) {
+ guard let value = value else {
+ buf.writeInt(Int8(0))
+ return
+ }
+ buf.writeInt(Int8(1))
+ FfiConverterUInt64.write(value, into: buf)
+ }
+
+ static func read(from buf: Reader) throws -> SwiftType {
+ switch try buf.readInt() as Int8 {
+ case 0: return nil
+ case 1: return try FfiConverterUInt64.read(from: buf)
+ default: throw UniffiInternalError.unexpectedOptionalTag
+ }
+ }
+}
+
+fileprivate struct FfiConverterOptionTypeFpUrl: FfiConverterRustBuffer {
+ typealias SwiftType = FpUrl?
+
+ static func write(_ value: SwiftType, into buf: Writer) {
+ guard let value = value else {
+ buf.writeInt(Int8(0))
+ return
+ }
+ buf.writeInt(Int8(1))
+ FfiConverterTypeFpUrl.write(value, into: buf)
+ }
+
+ static func read(from buf: Reader) throws -> SwiftType {
+ switch try buf.readInt() as Int8 {
+ case 0: return nil
+ case 1: return try FfiConverterTypeFpUrl.read(from: buf)
+ default: throw UniffiInternalError.unexpectedOptionalTag
+ }
+ }
+}
+
+
+/**
+ * Top level initializers and tear down methods.
+ *
+ * This is generated by uniffi.
+ */
+public enum FeatureProbeLifecycle {
+ /**
+ * Initialize the FFI and Rust library. This should be only called once per application.
+ */
+ func initialize() {
+
+ // No initialization code needed
+
+ }
+}
\ No newline at end of file
diff --git a/Sources/FeatureProbe/ObjcFeatureProbe.swift b/Sources/FeatureProbe/ObjcFeatureProbe.swift
new file mode 100644
index 0000000..1d3a233
--- /dev/null
+++ b/Sources/FeatureProbe/ObjcFeatureProbe.swift
@@ -0,0 +1,233 @@
+import Foundation
+
+@objc(FpConfig)
+public final class OFpConfig: NSObject {
+ var config: FpConfig
+
+ @objc public init(remoteUrl: OFpUrl, clientSdkKey: String, refreshInterval: UInt8, waitFirstResp: Bool) {
+ let remoteUrl = remoteUrl._url
+ config = FpConfig(remoteUrl: remoteUrl, clientSdkKey: clientSdkKey, refreshInterval: refreshInterval, waitFirstResp: waitFirstResp)
+ }
+
+}
+
+@objc(FeatureProbe)
+public final class OcFeatureProbe: NSObject {
+ var fp: FeatureProbe
+
+ @objc public init(config: OFpConfig, user: OFpUser) {
+ let config = config.config
+ let user = user.user
+ fp = FeatureProbe(config: config, user: user)
+ }
+
+ @objc public func boolValue(key: String, defaultValue: Bool) -> Bool {
+ fp.boolValue(key: key, defaultValue: defaultValue)
+ }
+
+ @objc public func boolDetail(key: String, defaultValue: Bool) -> OFpBoolDetail {
+ let d = fp.boolDetail(key: key, defaultValue: defaultValue)
+ return OFpBoolDetail(detail: d)
+ }
+
+ @objc public func numberValue(key: String, defaultValue: Double) -> Double {
+ fp.numberValue(key: key, defaultValue: defaultValue)
+ }
+
+ @objc public func numberDetail(key: String, defaultValue: Double) -> OFpNumberDetail {
+ let d = fp.numberDetail(key: key, defaultValue: defaultValue)
+ return OFpNumberDetail(detail: d)
+ }
+
+ @objc public func stringValue(key: String, defaultValue: String) -> String {
+ fp.stringValue(key: key, defaultValue: defaultValue)
+ }
+
+ @objc public func stringDetail(key: String, defaultValue: String) -> OFpStringDetail {
+ let d = fp.stringDetail(key: key, defaultValue: defaultValue)
+ return OFpStringDetail(detail: d)
+ }
+
+ @objc public func jsonValue(key: String, defaultValue: String) -> String {
+ fp.jsonValue(key: key, defaultValue: defaultValue)
+ }
+
+ @objc public func jsonDetail(key: String, defaultValue: String) -> OFpJsonDetail {
+ let d = fp.jsonDetail(key: key, defaultValue: defaultValue)
+ return OFpJsonDetail(detail: d)
+ }
+
+}
+
+@objc(FpUser)
+public final class OFpUser: NSObject {
+ var user: FpUser
+
+ @objc public init(key: String) {
+ let u = FpUser(key: key)
+ user = u
+ }
+
+ @objc public func setAttr(key: String, value: String) {
+ user.setAttr(key: key, value: value)
+ }
+}
+
+@objc(FpUrl)
+public final class OFpUrl: NSObject {
+ var _url: FpUrl
+
+ public init(url: FpUrl) {
+ _url = url
+ }
+}
+
+@objc(FpUrlBuilder)
+public final class OFpUrlBuilder: NSObject {
+ var builder: FpUrlBuilder
+
+ @objc public init(remoteUrl: String) {
+ builder = FpUrlBuilder(remoteUrl: remoteUrl)
+ }
+
+ @objc public func build() -> OFpUrl? {
+ let url = builder.build();
+ if url == nil {
+ return nil
+ }
+ return OFpUrl(url: url!)
+ }
+
+}
+
+@objc(FpBoolDetail)
+public final class OFpBoolDetail: NSObject {
+ var _detail: FpBoolDetail
+
+ public init(detail: FpBoolDetail) {
+ _detail = detail
+ }
+
+ @objc public var value: Bool {
+ _detail.value
+ }
+
+ @objc public var ruleIndex: NSNumber {
+ if _detail.ruleIndex == nil {
+ return -1
+ } else {
+ return _detail.ruleIndex! as NSNumber
+ }
+ }
+
+ @objc public var version: NSNumber {
+ if _detail.version == nil {
+ return -1
+ } else {
+ return _detail.version! as NSNumber
+ }
+ }
+
+ @objc public var reason: String {
+ _detail.reason
+ }
+}
+
+@objc(FpNumberDetail)
+public final class OFpNumberDetail: NSObject {
+ var _detail: FpNumDetail
+
+ public init(detail: FpNumDetail) {
+ _detail = detail
+ }
+
+ @objc public var value: Double {
+ _detail.value
+ }
+
+ @objc public var ruleIndex: NSNumber {
+ if _detail.ruleIndex == nil {
+ return -1
+ } else {
+ return _detail.ruleIndex! as NSNumber
+ }
+ }
+
+ @objc public var version: NSNumber {
+ if _detail.version == nil {
+ return -1
+ } else {
+ return _detail.version! as NSNumber
+ }
+ }
+
+ @objc public var reason: String {
+ _detail.reason
+ }
+}
+
+@objc(FpStringDetail)
+public final class OFpStringDetail: NSObject {
+ var _detail: FpStrDetail
+
+ public init(detail: FpStrDetail) {
+ _detail = detail
+ }
+
+ @objc public var value: String {
+ _detail.value
+ }
+
+ @objc public var ruleIndex: NSNumber {
+ if _detail.ruleIndex == nil {
+ return -1
+ } else {
+ return _detail.ruleIndex! as NSNumber
+ }
+ }
+
+ @objc public var version: NSNumber {
+ if _detail.version == nil {
+ return -1
+ } else {
+ return _detail.version! as NSNumber
+ }
+ }
+
+ @objc public var reason: String {
+ _detail.reason
+ }
+}
+
+@objc(FpJsonDetail)
+public final class OFpJsonDetail: NSObject {
+ var _detail: FpJsonDetail
+
+ public init(detail: FpJsonDetail) {
+ _detail = detail
+ }
+
+ @objc public var value: String {
+ _detail.value
+ }
+
+ @objc public var ruleIndex: NSNumber {
+ if _detail.ruleIndex == nil {
+ return -1
+ } else {
+ return _detail.ruleIndex! as NSNumber
+ }
+ }
+
+ @objc public var version: NSNumber {
+ if _detail.version == nil {
+ return -1
+ } else {
+ return _detail.version! as NSNumber
+ }
+ }
+
+ @objc public var reason: String {
+ _detail.reason
+ }
+}