diff --git a/.gitignore b/.gitignore
index 4ba439ba4..aebccc6ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,4 +56,10 @@ Thumbs.db
# types
ios-typings-prj
-.nx/cache
\ No newline at end of file
+.nx/cache
+
+#rust
+/target
+
+#android
+.cxx
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 000000000..cbb446ba9
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,195 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "ada-url"
+version = "2.1.0"
+source = "git+https://github.com/triniwiz/ada-url-rust?rev=bc35ae9#bc35ae9c54d96a18655d5069ad4b63829c9beb31"
+dependencies = [
+ "cc",
+ "derive_more",
+ "link_args",
+ "regex",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "base64"
+version = "0.21.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
+
+[[package]]
+name = "bytes"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
+
+[[package]]
+name = "cc"
+version = "1.0.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
+dependencies = [
+ "jobserver",
+ "libc",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "convert_case"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+
+[[package]]
+name = "derive_more"
+version = "0.99.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn",
+]
+
+[[package]]
+name = "encoding_rs"
+version = "0.8.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "jobserver"
+version = "0.1.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.151"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+
+[[package]]
+name = "link_args"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c7721e472624c9aaad27a5eb6b7c9c6045c7a396f2efb6dabaec1b640d5e89b"
+
+[[package]]
+name = "memchr"
+version = "2.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+
+[[package]]
+name = "nativescript-core"
+version = "0.1.0"
+dependencies = [
+ "ada-url",
+ "base64",
+ "bytes",
+ "encoding_rs",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.76"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 000000000..18dbd19a1
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,18 @@
+[workspace]
+members = [
+ "crates/libs/*"
+]
+
+resolver = "2"
+
+#[dev.release]
+#panic = "abort"
+
+[profile.release]
+panic = "abort"
+codegen-units = 1
+lto = true
+opt-level = 3
+debug = false
+incremental = false
+strip = true
\ No newline at end of file
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..e6b03ed2c
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,45 @@
+ARCHS_IOS = x86_64-apple-ios aarch64-apple-ios aarch64-apple-ios-sim
+ARCHS_ANDROID = i686-linux-android x86_64-linux-android aarch64-linux-android armv7-linux-androideabi
+LIB = libnativescriptcore.dylib
+XCFRAMEWORK = NativeScriptCore.xcframework
+RUST_LIB = nativescriptcore
+
+all:GENERATE_HEADERS ios android
+
+ios: $(XCFRAMEWORK)
+
+android: GENERATE_ANDROID
+
+
+.PHONY: android_only
+android_only: GENERATE_HEADERS android
+
+.PHONY: ios_only
+ios_only: GENERATE_HEADERS android
+
+.PHONY: GENERATE_HEADERS
+GENERATE_HEADERS:
+ ./tools/scripts/build-rust-headers.sh
+
+# PHONY keyword on make means this is not a file, just an identifier for a target
+.PHONY: $(ARCHS_IOS)
+$(ARCHS_IOS): %:
+ cargo +nightly build -Z build-std='std,panic_abort' -Z build-std-features=panic_immediate_abort --target $@ --release -p nativescript-core
+
+$(XCFRAMEWORK): $(ARCHS_IOS)
+ rm -rf target/simulator_fat
+ mkdir target/simulator_fat
+ lipo -create $(wildcard target/x86_64-apple-ios/release/$(LIB)) $(wildcard target/aarch64-apple-ios-sim/release/$(LIB)) -output target/simulator_fat/$(LIB)
+ xcodebuild -create-xcframework -library $(wildcard target/aarch64-apple-ios/release/$(LIB)) -headers crates/libs/nativescript-core/include -library target/simulator_fat/$(LIB) -headers crates/libs/nativescript-core/include -output target/$@ && ./tools/scripts/copy-rust-ios.sh
+
+.PHONY: $(ARCHS_ANDROID)
+$(ARCHS_ANDROID): %:
+ ./tools/scripts/build-rust-android.sh $@
+
+.PHONY: GENERATE_ANDROID
+GENERATE_ANDROID: $(ARCHS_ANDROID)
+ ./tools/scripts/copy-rust-android.sh
+
+.PHONY: clean
+clean:
+ rm -rf target rm -rf $(XCFRAMEWORK) rm -rf simulator_fat/$(LIB)
\ No newline at end of file
diff --git a/apps/toolbox/src/main-page.xml b/apps/toolbox/src/main-page.xml
index 0588cfa03..0af69c510 100644
--- a/apps/toolbox/src/main-page.xml
+++ b/apps/toolbox/src/main-page.xml
@@ -25,6 +25,7 @@
+
diff --git a/apps/toolbox/src/pages/wintercg.ts b/apps/toolbox/src/pages/wintercg.ts
new file mode 100644
index 000000000..268af9c47
--- /dev/null
+++ b/apps/toolbox/src/pages/wintercg.ts
@@ -0,0 +1,70 @@
+import { Page, EventData } from '@nativescript/core';
+
+let page: Page;
+
+export function navigatingTo(args: EventData) {
+ page = args.object;
+}
+
+export function createURL() {
+ const url = new URL('../cats', 'http://www.example.com/dogs');
+ console.log(url.hostname); // "www.example.com"
+ console.log(url.pathname); // "/cats"
+
+ if (URL.canParse('../cats', 'http://www.example.com/dogs')) {
+ const url = new URL('../cats', 'http://www.example.com/dogs');
+ console.log(url.hostname); // "www.example.com"
+ console.log(url.pathname); // "/cats"
+ } else {
+ console.log('Invalid URL'); //Invalid URL
+ }
+
+ url.hash = 'tabby';
+ console.log(url.href); // "http://www.example.com/cats#tabby"
+
+ url.pathname = 'démonstration.html';
+ console.log(url.href); // "http://www.example.com/d%C3%A9monstration.html"
+}
+
+let encoded;
+let encodedBase64;
+export function encode() {
+ const encoder = new TextEncoder();
+ encoded = encoder.encode(txt);
+}
+
+export function decode() {
+ const decoder = new TextDecoder();
+ const eq = decoder.decode(encoded) === txt;
+ console.log('decode: equal', eq);
+}
+
+export function atobFunc() {
+ const eq = atob(encodedBase64) === txt;
+
+ console.log('atob: equal', eq);
+}
+
+export function btoaFunc() {
+ encodedBase64 = btoa(txt);
+}
+
+const txt = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent ac tortor congue, pharetra elit a, volutpat erat. Etiam vel ornare quam. Integer vitae sapien malesuada tellus iaculis ultrices. In hac habitasse platea dictumst. Nulla enim magna, blandit vel massa ac, bibendum viverra tortor. Nam accumsan mi eu risus pretium sollicitudin vitae ut nibh. Vivamus lorem diam, sagittis vel leo vel, pharetra aliquam ex. Aenean sollicitudin fringilla ex. Donec malesuada justo enim. Fusce elementum velit quis quam varius, sit amet feugiat sapien faucibus. Vestibulum nec tincidunt nibh, sit amet sagittis tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae;
+
+Vivamus vehicula eros et libero interdum, vitae volutpat augue finibus. Integer pretium, arcu sed blandit lobortis, tortor purus mollis eros, non fringilla leo arcu nec risus. Quisque cursus diam quam. Morbi id gravida quam, nec dapibus lorem. Duis egestas quis eros a aliquam. In suscipit est porta, dictum metus ac, efficitur odio. Aliquam convallis sem sit amet nunc malesuada placerat. Maecenas convallis, diam eu condimentum pulvinar, quam diam pretium justo, id mattis massa enim a erat.
+
+Nulla maximus elementum turpis id elementum. Nulla enim est, vehicula a odio sed, aliquet posuere risus. Ut vitae cursus magna. Proin ut tortor non ipsum laoreet hendrerit nec tincidunt lectus. Vestibulum congue commodo purus vel condimentum. Ut ut mattis diam. Suspendisse sagittis viverra scelerisque. Donec mattis dictum efficitur. Nulla rhoncus ipsum eget finibus varius. Suspendisse cursus eget turpis congue rutrum. Proin scelerisque eget purus et ornare. Proin placerat turpis eu tortor placerat facilisis. Suspendisse potenti.
+
+In lacinia finibus elit, id varius eros aliquam suscipit. Donec scelerisque felis at finibus molestie. Etiam suscipit lectus ac libero dignissim imperdiet. Nunc at sollicitudin elit, commodo tincidunt sapien. Vivamus tempor elit a mi dapibus, et sollicitudin felis aliquam. Pellentesque luctus malesuada urna, at semper sem ullamcorper a. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Quisque in vestibulum massa, et sollicitudin lorem. Integer euismod sem nec purus viverra laoreet. Nunc pretium commodo turpis, a auctor mi dictum sed. Maecenas egestas euismod volutpat.
+
+Cras magna sapien, faucibus id molestie vel, ullamcorper non tortor. Vestibulum pulvinar tempus turpis ut congue. Etiam eu tristique diam. Curabitur nunc ipsum, dictum sit amet scelerisque sit amet, dictum ut est. Etiam eget dolor faucibus, iaculis nisi sed, dapibus mauris. Vivamus porttitor nunc in justo fringilla, ut pulvinar nulla sagittis. Integer fringilla turpis et metus fermentum, a volutpat neque iaculis.
+
+Vivamus congue congue libero, lobortis fringilla felis rutrum eget. Etiam egestas augue id volutpat sagittis. Aenean eget felis euismod, faucibus mauris et, convallis tellus. Sed lectus tellus, mollis eu odio non, malesuada fermentum turpis. In eget varius elit, in consectetur odio. Nunc ullamcorper mauris pulvinar odio consectetur ultricies. Cras venenatis metus neque, a dignissim risus faucibus quis. Ut suscipit eros sit amet nisl sodales, vitae sollicitudin justo accumsan. Vivamus pellentesque convallis suscipit. Sed in velit dui.
+
+Fusce nec sem fringilla, fringilla mi non, efficitur felis. Duis suscipit sit amet metus eu bibendum. Mauris ac mattis neque. Ut et lacus vitae lorem fermentum rutrum sit amet vitae purus. Cras eget nulla interdum, placerat nibh nec, auctor odio. Vivamus eget turpis eros. Nulla ut suscipit magna. Morbi vel ultrices tellus. Maecenas et dui vitae mi convallis laoreet eget eget nibh. Pellentesque auctor dui lacus, sit amet venenatis urna posuere in.
+
+Aliquam consequat posuere ante id tristique. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nunc ac tellus arcu. Duis ac risus eleifend nisi molestie tincidunt. Morbi non lectus libero. Sed tellus est, scelerisque vel arcu vel, facilisis faucibus magna. Donec odio eros, tristique non tortor eu, ullamcorper lobortis purus. Nunc tristique metus sit amet lobortis consequat. Donec vitae lacinia sapien, eu dapibus justo. Donec mattis dolor molestie fringilla dapibus. Mauris tristique molestie porta. Suspendisse eget mattis justo, in varius metus. Phasellus faucibus ligula vitae maximus congue. Vestibulum arcu odio, viverra vitae dui sit amet, gravida congue ligula. Nulla est magna, rutrum eget neque ullamcorper, aliquam cursus odio.
+
+Ut in est ipsum. Duis eget quam ex. Quisque dapibus imperdiet libero, a ullamcorper nunc consectetur ut. Integer sed ullamcorper orci. Vestibulum a enim sed odio convallis pulvinar. Duis pulvinar tempor porta. Cras sem nunc, aliquet nec placerat sed, mattis vel tortor. Donec mattis luctus finibus. Donec nibh eros, elementum eu quam quis, iaculis aliquam sapien. Donec vitae facilisis metus. Sed semper porttitor purus nec vestibulum. Proin mollis mauris sit amet mauris fringilla, fermentum dapibus lectus congue. Etiam in mauris ante. Nullam sit amet fermentum lorem, at vulputate mauris.
+
+Integer magna quam, fringilla ut neque id, porta suscipit elit. Morbi feugiat mattis orci, ut hendrerit orci viverra nec. Curabitur laoreet laoreet molestie. Fusce condimentum feugiat lorem, vel vestibulum ante sodales bibendum. Aliquam quis semper libero. Fusce auctor nunc accumsan sagittis pharetra. Donec sagittis magna ac blandit lobortis. Nam volutpat posuere eros, vitae finibus ex aliquam a. Sed dapibus imperdiet nisi nec egestas. In et pharetra orci, ac gravida lacus. Donec condimentum velit libero, id venenatis odio lacinia quis.`;
diff --git a/apps/toolbox/src/pages/wintercg.xml b/apps/toolbox/src/pages/wintercg.xml
new file mode 100644
index 000000000..24359c10e
--- /dev/null
+++ b/apps/toolbox/src/pages/wintercg.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/crates/README.md b/crates/README.md
new file mode 100644
index 000000000..6f6362a63
--- /dev/null
+++ b/crates/README.md
@@ -0,0 +1,20 @@
+## Rust
+
+For building the iOS and Android packages the following targets are required
+
+### Android
+
+`rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android`
+
+## Build Android
+
+To build android only run `make android_only`
+
+### iOS
+
+`rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios`
+
+To build android only run `make ios_only`
+
+
+To build both packages run `make all`
\ No newline at end of file
diff --git a/crates/libs/nativescript-core/Cargo.toml b/crates/libs/nativescript-core/Cargo.toml
new file mode 100644
index 000000000..905f360cb
--- /dev/null
+++ b/crates/libs/nativescript-core/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "nativescript-core"
+version = "0.1.0"
+edition = "2021"
+
+[build]
+rustflags = ["-Cpanic=abort", "-C target-cpu=native", "-C target-feature=-outline-atomics"]
+
+
+[lib]
+name = "nativescriptcore"
+crate-type = ["cdylib", "staticlib"]
+
+
+[dependencies]
+ada-url = {git = "https://github.com/triniwiz/ada-url-rust" , rev = "bc35ae9"}
+encoding_rs = "0.8.33"
+bytes = "1.5.0"
+base64 = "0.21.5"
\ No newline at end of file
diff --git a/crates/libs/nativescript-core/cbindgen.toml b/crates/libs/nativescript-core/cbindgen.toml
new file mode 100644
index 000000000..b02d76ae6
--- /dev/null
+++ b/crates/libs/nativescript-core/cbindgen.toml
@@ -0,0 +1,11 @@
+autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
+language = "C"
+namespace = "ffi"
+include_guard = "CBINDGEN_BINDINGS_H"
+
+[defines]
+"target_os = ios" = "TARGET_OS_IOS"
+"target_os = macos" = "TARGET_OS_MACOS"
+"target_os = android" = "TARGET_OS_ANDROID"
+"target_os = windows" = "TARGET_OS_WINDOWS"
+"target_os = linux" = "TARGET_OS_LINUX"
\ No newline at end of file
diff --git a/crates/libs/nativescript-core/include/nativescript_core.h b/crates/libs/nativescript-core/include/nativescript_core.h
new file mode 100644
index 000000000..fb2148370
--- /dev/null
+++ b/crates/libs/nativescript-core/include/nativescript_core.h
@@ -0,0 +1,171 @@
+#ifndef CBINDGEN_BINDINGS_H
+#define CBINDGEN_BINDINGS_H
+
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#include
+#include
+#include
+#include
+
+typedef struct CCow CCow;
+
+typedef struct F32Buffer F32Buffer;
+
+typedef struct I32Buffer I32Buffer;
+
+typedef struct StringBuffer StringBuffer;
+
+typedef struct TextDecoder TextDecoder;
+
+typedef struct TextEncoder TextEncoder;
+
+typedef struct U16Buffer U16Buffer;
+
+typedef struct U32Buffer U32Buffer;
+
+typedef struct U8Buffer U8Buffer;
+
+typedef struct URL URL;
+
+struct U8Buffer *nativescript_core_atob(const char *value);
+
+struct U8Buffer *nativescript_core_atob_ccow(const struct CCow *value);
+
+struct CCow *nativescript_core_btoa(const char *value);
+
+struct CCow *nativescript_core_btoa_ccow(const struct CCow *value);
+
+void nativescript_core_string_destroy(char *value);
+
+bool nativescript_core_url_can_parse(const char *value, const char *base);
+
+struct URL *nativescript_core_url_create(const char *value, const char *base);
+
+void nativescript_core_url_destroy(struct URL *url);
+
+struct CCow *nativescript_core_url_to_string(struct URL *url);
+
+const char *nativescript_core_url_hash(struct URL *url);
+
+void nativescript_core_url_set_hash(struct URL *url, const char *hash);
+
+const char *nativescript_core_url_host(struct URL *url);
+
+void nativescript_core_url_set_host(struct URL *url, const char *host);
+
+const char *nativescript_core_url_host_name(struct URL *url);
+
+void nativescript_core_url_set_host_name(struct URL *url, const char *hostname);
+
+const char *nativescript_core_url_href(struct URL *url);
+
+void nativescript_core_url_set_href(struct URL *url, const char *href);
+
+const char *nativescript_core_url_origin(struct URL *url);
+
+const char *nativescript_core_url_password(struct URL *url);
+
+void nativescript_core_url_set_password(struct URL *url, const char *password);
+
+const char *nativescript_core_url_pathname(struct URL *url);
+
+void nativescript_core_url_set_pathname(struct URL *url, const char *pathname);
+
+const char *nativescript_core_url_port(struct URL *url);
+
+void nativescript_core_url_set_port(struct URL *url, const char *port);
+
+const char *nativescript_core_url_protocol(struct URL *url);
+
+void nativescript_core_url_set_protocol(struct URL *url, const char *protocol);
+
+const char *nativescript_core_url_search(struct URL *url);
+
+void nativescript_core_url_set_search(struct URL *url, const char *search);
+
+const char *nativescript_core_url_username(struct URL *url);
+
+void nativescript_core_url_set_username(struct URL *url, const char *username);
+
+void nativescript_core_ccow_destroy(struct CCow *cow);
+
+const uint8_t *nativescript_core_ccow_get_bytes(const struct CCow *cow);
+
+uintptr_t nativescript_core_ccow_get_length(const struct CCow *cow);
+
+struct TextDecoder *nativescript_core_text_decoder_create(const char *decoding);
+
+const char *nativescript_core_text_decoder_decode(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+struct CCow *nativescript_core_text_decoder_decode_as_cow(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+struct U8Buffer *nativescript_core_text_decoder_decode_as_bytes(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+void nativescript_core_text_decoder_destroy(struct TextDecoder *value);
+
+const char *nativescript_core_text_decoder_get_encoding(const struct TextDecoder *decoder);
+
+struct TextEncoder *nativescript_core_text_encoder_create(const char *encoding);
+
+struct U8Buffer *nativescript_core_text_encoder_encode(const struct TextEncoder *encoder,
+ const char *text);
+
+const char *nativescript_core_text_encoder_get_encoding(const struct TextEncoder *encoder);
+
+void nativescript_core_text_encoder_destroy(struct TextEncoder *value);
+
+const uint8_t *nativescript_core_u8_buffer_get_bytes(const struct U8Buffer *buffer);
+
+uint8_t *nativescript_core_u8_buffer_get_bytes_mut(struct U8Buffer *buffer);
+
+void nativescript_core_u8_buffer_destroy(struct U8Buffer *buffer);
+
+uintptr_t nativescript_core_u8_buffer_get_length(const struct U8Buffer *buffer);
+
+const uint16_t *nativescript_core_u16_buffer_get_bytes(const struct U16Buffer *buffer);
+
+uint16_t *nativescript_core_u16_buffer_get_bytes_mut(struct U16Buffer *buffer);
+
+void nativescript_core_u16_buffer_destroy(struct U16Buffer *buffer);
+
+uintptr_t nativescript_core_u16_buffer_get_length(const struct U16Buffer *buffer);
+
+const uint32_t *nativescript_core_u32_buffer_get_bytes(const struct U32Buffer *buffer);
+
+uint32_t *nativescript_core_u32_buffer_get_bytes_mut(struct U32Buffer *buffer);
+
+void nativescript_core_u32_buffer_destroy(struct U32Buffer *buffer);
+
+uintptr_t nativescript_core_u32_buffer_get_length(const struct U32Buffer *buffer);
+
+const int32_t *nativescript_core_i32_buffer_get_bytes(const struct I32Buffer *buffer);
+
+int32_t *nativescript_core_i32_buffer_get_bytes_mut(struct I32Buffer *buffer);
+
+void nativescript_core_i32_buffer_destroy(struct I32Buffer *buffer);
+
+uintptr_t nativescript_core_i32_buffer_get_length(const struct I32Buffer *buffer);
+
+const float *nativescript_core_f32_buffer_get_bytes(const struct F32Buffer *buffer);
+
+float *nativescript_core_f32_buffer_get_bytes_mut(struct F32Buffer *buffer);
+
+void nativescript_core_f32_buffer_destroy(struct F32Buffer *buffer);
+
+uintptr_t nativescript_core_f32_buffer_get_length(const struct F32Buffer *buffer);
+
+uintptr_t nativescript_core_string_buffer_get_length(const struct StringBuffer *buffer);
+
+char *nativescript_core_string_buffer_get_value_at(const struct StringBuffer *buffer,
+ uintptr_t index);
+
+void nativescript_core_string_buffer_destroy(struct StringBuffer *buffer);
+
+#endif /* CBINDGEN_BINDINGS_H */
diff --git a/crates/libs/nativescript-core/src/buffers.rs b/crates/libs/nativescript-core/src/buffers.rs
new file mode 100644
index 000000000..101ef7ac0
--- /dev/null
+++ b/crates/libs/nativescript-core/src/buffers.rs
@@ -0,0 +1,434 @@
+use std::ffi::{c_char, CString};
+
+use bytes::BytesMut;
+
+#[derive(Clone)]
+enum U8BufferInner {
+ BytesMut(BytesMut),
+ Vec(Vec),
+}
+
+#[derive(Clone)]
+pub struct U8Buffer(U8BufferInner);
+
+impl U8Buffer {
+ pub fn new_with_vec(value: Vec) -> Self {
+ Self(U8BufferInner::Vec(value))
+ }
+
+ pub fn get_buffer(&self) -> &[u8] {
+ match &self.0 {
+ U8BufferInner::BytesMut(value) => value,
+ U8BufferInner::Vec(value) => value.as_slice(),
+ }
+ }
+
+ pub fn get_buffer_mut(&mut self) -> &mut [u8] {
+ match &mut self.0 {
+ U8BufferInner::BytesMut(value) => value,
+ U8BufferInner::Vec(value) => value.as_mut_slice(),
+ }
+ }
+
+ pub fn length(&self) -> usize {
+ match &self.0 {
+ U8BufferInner::BytesMut(value) => value.len(),
+ U8BufferInner::Vec(value) => value.len(),
+ }
+ }
+}
+
+impl Default for U8Buffer {
+ fn default() -> Self {
+ Self(U8BufferInner::BytesMut(BytesMut::default()))
+ }
+}
+
+impl From> for U8Buffer {
+ fn from(value: Vec) -> Self {
+ U8Buffer(U8BufferInner::Vec(value))
+ }
+}
+
+impl From for U8Buffer {
+ fn from(value: BytesMut) -> Self {
+ U8Buffer(U8BufferInner::BytesMut(value))
+ }
+}
+
+pub struct U16Buffer(Vec);
+
+impl U16Buffer {
+ pub fn new_with_vec(value: Vec) -> Self {
+ Self(value)
+ }
+
+ pub fn get_buffer(&self) -> &[u16] {
+ self.0.as_slice()
+ }
+
+ pub fn get_buffer_mut(&mut self) -> &mut [u16] {
+ self.0.as_mut_slice()
+ }
+
+ pub fn length(&self) -> usize {
+ self.0.len()
+ }
+}
+
+impl Default for U16Buffer {
+ fn default() -> Self {
+ Self(Vec::new())
+ }
+}
+
+impl From> for U16Buffer {
+ fn from(value: Vec) -> Self {
+ Self::new_with_vec(value)
+ }
+}
+
+pub struct F32Buffer(Vec);
+
+impl F32Buffer {
+ pub fn new_with_vec(value: Vec) -> Self {
+ Self(value)
+ }
+
+ pub fn get_buffer(&self) -> &[f32] {
+ self.0.as_slice()
+ }
+
+ pub fn get_buffer_mut(&mut self) -> &mut [f32] {
+ self.0.as_mut_slice()
+ }
+
+ pub fn length(&self) -> usize {
+ self.0.len()
+ }
+}
+
+impl Default for F32Buffer {
+ fn default() -> Self {
+ Self(Vec::new())
+ }
+}
+
+impl From> for F32Buffer {
+ fn from(value: Vec) -> Self {
+ Self(value)
+ }
+}
+
+pub struct I32Buffer(Vec);
+
+impl I32Buffer {
+ pub fn new_with_vec(value: Vec) -> Self {
+ Self(value)
+ }
+ pub fn get_buffer(&self) -> &[i32] {
+ self.0.as_slice()
+ }
+
+ pub fn get_buffer_mut(&mut self) -> &mut [i32] {
+ self.0.as_mut_slice()
+ }
+
+ pub fn length(&self) -> usize {
+ self.0.len()
+ }
+}
+
+impl Default for I32Buffer {
+ fn default() -> Self {
+ Self(Vec::new())
+ }
+}
+
+impl From> for I32Buffer {
+ fn from(value: Vec) -> Self {
+ Self(value)
+ }
+}
+
+pub struct U32Buffer(Vec);
+
+impl U32Buffer {
+ pub fn new_with_vec(value: Vec) -> Self {
+ Self(value)
+ }
+
+ pub fn get_buffer(&self) -> &[u32] {
+ self.0.as_slice()
+ }
+
+ pub fn get_buffer_mut(&mut self) -> &mut [u32] {
+ self.0.as_mut_slice()
+ }
+
+ pub fn length(&self) -> usize {
+ self.0.len()
+ }
+}
+
+impl Default for U32Buffer {
+ fn default() -> Self {
+ Self::new_with_vec(Vec::new())
+ }
+}
+
+impl From> for U32Buffer {
+ fn from(value: Vec) -> Self {
+ Self::new_with_vec(value)
+ }
+}
+
+pub struct StringBuffer(Vec);
+
+impl From> for StringBuffer {
+ fn from(value: Vec) -> Self {
+ Self(value)
+ }
+}
+
+impl StringBuffer {
+ pub fn get_buffer(&self) -> &[String] {
+ self.0.as_slice()
+ }
+
+ pub fn length(&self) -> usize {
+ self.0.len()
+ }
+}
+
+pub struct StringRefBuffer<'a>(&'a [&'a str]);
+
+impl<'a> StringRefBuffer<'a> {
+ pub fn get_buffer(&self) -> &[&str] {
+ self.0
+ }
+
+ pub fn length(&self) -> usize {
+ self.0.len()
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u8_buffer_get_bytes(buffer: *const U8Buffer) -> *const u8 {
+ if buffer.is_null() {
+ return std::ptr::null();
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.get_buffer().as_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u8_buffer_get_bytes_mut(buffer: *mut U8Buffer) -> *mut u8 {
+ if buffer.is_null() {
+ return std::ptr::null_mut();
+ }
+ let buffer = unsafe { &mut *buffer };
+ buffer.get_buffer_mut().as_mut_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u8_buffer_destroy(buffer: *mut U8Buffer) {
+ if buffer.is_null() {
+ return;
+ }
+ unsafe {
+ let _ = Box::from_raw(buffer);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u8_buffer_get_length(buffer: *const U8Buffer) -> usize {
+ if buffer.is_null() {
+ return 0;
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.length()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u16_buffer_get_bytes(buffer: *const U16Buffer) -> *const u16 {
+ if buffer.is_null() {
+ return std::ptr::null();
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.get_buffer().as_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u16_buffer_get_bytes_mut(buffer: *mut U16Buffer) -> *mut u16 {
+ if buffer.is_null() {
+ return std::ptr::null_mut();
+ }
+ let buffer = unsafe { &mut *buffer };
+ buffer.get_buffer_mut().as_mut_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u16_buffer_destroy(buffer: *mut U16Buffer) {
+ if buffer.is_null() {
+ return;
+ }
+ unsafe {
+ let _ = Box::from_raw(buffer);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u16_buffer_get_length(buffer: *const U16Buffer) -> usize {
+ if buffer.is_null() {
+ return 0;
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.length()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u32_buffer_get_bytes(buffer: *const U32Buffer) -> *const u32 {
+ if buffer.is_null() {
+ return std::ptr::null();
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.get_buffer().as_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u32_buffer_get_bytes_mut(buffer: *mut U32Buffer) -> *mut u32 {
+ if buffer.is_null() {
+ return std::ptr::null_mut();
+ }
+ let buffer = unsafe { &mut *buffer };
+ buffer.get_buffer_mut().as_mut_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u32_buffer_destroy(buffer: *mut U32Buffer) {
+ if buffer.is_null() {
+ return;
+ }
+ unsafe {
+ let _ = Box::from_raw(buffer);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_u32_buffer_get_length(buffer: *const U32Buffer) -> usize {
+ if buffer.is_null() {
+ return 0;
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.length()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_i32_buffer_get_bytes(buffer: *const I32Buffer) -> *const i32 {
+ if buffer.is_null() {
+ return std::ptr::null();
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.get_buffer().as_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_i32_buffer_get_bytes_mut(buffer: *mut I32Buffer) -> *mut i32 {
+ if buffer.is_null() {
+ return std::ptr::null_mut();
+ }
+ let buffer = unsafe { &mut *buffer };
+ buffer.get_buffer_mut().as_mut_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_i32_buffer_destroy(buffer: *mut I32Buffer) {
+ if buffer.is_null() {
+ return;
+ }
+ unsafe {
+ let _ = Box::from_raw(buffer);
+ }
+}
+
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_i32_buffer_get_length(buffer: *const I32Buffer) -> usize {
+ if buffer.is_null() {
+ return 0;
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.length()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_f32_buffer_get_bytes(buffer: *const F32Buffer) -> *const f32 {
+ if buffer.is_null() {
+ return std::ptr::null();
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.get_buffer().as_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_f32_buffer_get_bytes_mut(buffer: *mut F32Buffer) -> *mut f32 {
+ if buffer.is_null() {
+ return std::ptr::null_mut();
+ }
+ let buffer = unsafe { &mut *buffer };
+ buffer.get_buffer_mut().as_mut_ptr()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_f32_buffer_destroy(buffer: *mut F32Buffer) {
+ if buffer.is_null() {
+ return;
+ }
+ unsafe {
+ let _ = Box::from_raw(buffer);
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_f32_buffer_get_length(buffer: *const F32Buffer) -> usize {
+ if buffer.is_null() {
+ return 0;
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.length()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_string_buffer_get_length(buffer: *const StringBuffer) -> usize {
+ if buffer.is_null() {
+ return 0;
+ }
+ let buffer = unsafe { &*buffer };
+ buffer.length()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_string_buffer_get_value_at(
+ buffer: *const StringBuffer,
+ index: usize,
+) -> *mut c_char {
+ if buffer.is_null() {
+ return std::ptr::null_mut();
+ }
+ let buffer = unsafe { &*buffer };
+ match buffer.0.get(index) {
+ None => std::ptr::null_mut(),
+ Some(value) => CString::new(value.to_string()).unwrap().into_raw(),
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_string_buffer_destroy(buffer: *mut StringBuffer) {
+ if buffer.is_null() {
+ return;
+ }
+ unsafe {
+ let _ = Box::from_raw(buffer);
+ }
+}
\ No newline at end of file
diff --git a/crates/libs/nativescript-core/src/ccow.rs b/crates/libs/nativescript-core/src/ccow.rs
new file mode 100644
index 000000000..bdc92a556
--- /dev/null
+++ b/crates/libs/nativescript-core/src/ccow.rs
@@ -0,0 +1,69 @@
+use std::borrow::Cow;
+
+#[derive(Clone, Debug)]
+pub(crate) enum CCowInner {
+ String(Cow<'static, str>),
+ Bytes(Cow<'static, [u8]>),
+}
+
+#[derive(Clone, Debug)]
+pub struct CCow(pub(crate) CCowInner);
+
+impl AsRef<[u8]> for CCow {
+ fn as_ref(&self) -> &[u8] {
+ match &self.0 {
+ CCowInner::String(value) => value.as_bytes(),
+ CCowInner::Bytes(value) => value.as_ref()
+ }
+ }
+}
+
+impl From for CCow {
+ fn from(value: String) -> Self {
+ Self(CCowInner::String(Cow::from(value)))
+ }
+}
+
+impl From<&'static [u8]> for CCow {
+ fn from(value: &'static [u8]) -> Self {
+ Self(CCowInner::Bytes(Cow::from(value)))
+ }
+}
+
+impl From> for CCow {
+ fn from(value: Cow<'static, str>) -> Self {
+ Self(CCowInner::String(value))
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_ccow_destroy(cow: *mut CCow) {
+ if cow.is_null() {
+ return;
+ }
+ let _ = unsafe { Box::from_raw(cow) };
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_ccow_get_bytes(cow: *const CCow) -> *const u8 {
+ if cow.is_null() {
+ return std::ptr::null();
+ }
+ let cow = unsafe { &*cow };
+ match &cow.0 {
+ CCowInner::String(value) => value.as_ptr(),
+ CCowInner::Bytes(value) => value.as_ptr()
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_ccow_get_length(cow: *const CCow) -> usize {
+ if cow.is_null() {
+ return 0;
+ }
+ let cow = unsafe { &*cow };
+ match &cow.0 {
+ CCowInner::String(value) => value.len(),
+ CCowInner::Bytes(value) => value.len()
+ }
+}
\ No newline at end of file
diff --git a/crates/libs/nativescript-core/src/lib.rs b/crates/libs/nativescript-core/src/lib.rs
new file mode 100644
index 000000000..f4087cc4c
--- /dev/null
+++ b/crates/libs/nativescript-core/src/lib.rs
@@ -0,0 +1,84 @@
+use std::ffi::{CStr, CString};
+use std::os::raw::c_char;
+
+use base64::Engine;
+
+use crate::buffers::U8Buffer;
+use crate::ccow::{CCow, CCowInner};
+
+pub mod url;
+pub mod ccow;
+pub mod text_decoder;
+pub mod text_encoder;
+pub mod buffers;
+
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_atob(value: *const c_char) -> *mut U8Buffer {
+ if value.is_null() {
+ return std::ptr::null_mut();
+ }
+ let value = unsafe { CStr::from_ptr(value) };
+ let value = value.to_string_lossy();
+ match base64::engine::general_purpose::STANDARD.decode(value.as_bytes()) {
+ Ok(value) => Box::into_raw(Box::new(U8Buffer::new_with_vec(value))),
+ Err(_) => std::ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_atob_ccow(value: *const CCow) -> *mut U8Buffer {
+ if value.is_null() {
+ return std::ptr::null_mut();
+ }
+ let value = unsafe { &*value };
+ let ret = match &value.0 {
+ CCowInner::String(value) => {
+ base64::engine::general_purpose::STANDARD.decode(value.as_bytes())
+ }
+ CCowInner::Bytes(value) => {
+ base64::engine::general_purpose::STANDARD.decode(value)
+ }
+ };
+
+ match ret {
+ Ok(value) => Box::into_raw(Box::new(U8Buffer::new_with_vec(value))),
+ Err(_) => std::ptr::null_mut(),
+ }
+}
+
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_btoa(value: *const c_char) -> *mut CCow {
+ if value.is_null() {
+ return std::ptr::null_mut();
+ }
+ let value = unsafe { CStr::from_ptr(value) };
+
+ let value = value.to_string_lossy();
+
+ Box::into_raw(
+ Box::new(CCow::from(base64::engine::general_purpose::STANDARD.encode(value.as_bytes())))
+ )
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_btoa_ccow(value: *const CCow) -> *mut CCow {
+ if value.is_null() {
+ return std::ptr::null_mut();
+ }
+ let value = unsafe { &*value };
+
+ Box::into_raw(
+ Box::new(CCow::from(base64::engine::general_purpose::STANDARD.encode(value)))
+ )
+}
+
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_string_destroy(value: *mut c_char) {
+ if value.is_null() {
+ return;
+ }
+ let _ = unsafe { CString::from_raw(value) };
+}
\ No newline at end of file
diff --git a/crates/libs/nativescript-core/src/text_decoder.rs b/crates/libs/nativescript-core/src/text_decoder.rs
new file mode 100644
index 000000000..6ff2588d8
--- /dev/null
+++ b/crates/libs/nativescript-core/src/text_decoder.rs
@@ -0,0 +1,171 @@
+use std::borrow::Cow;
+use std::ffi::{c_char, CStr, CString};
+
+use encoding_rs::UTF_8;
+
+use crate::buffers::U8Buffer;
+use crate::ccow::CCow;
+
+#[derive(Clone)]
+pub struct TextDecoder {
+ inner: &'static encoding_rs::Encoding,
+}
+
+impl TextDecoder {
+ pub fn new(decoding: Option<&str>) -> Self {
+ let decoding = decoding.unwrap_or("utf-8");
+ let decoder = encoding_rs::Encoding::for_label(decoding.as_bytes())
+ .unwrap_or(UTF_8.output_encoding());
+ Self { inner: decoder }
+ }
+
+ pub fn decode_to_string(&self, data: &[u8]) -> String {
+ let (res, _) = self.inner.decode_with_bom_removal(data);
+
+ match CStr::from_bytes_with_nul(res.as_bytes()) {
+ Ok(res) => res.to_string_lossy().to_string(),
+ Err(_) => res.chars().filter(|&c| c != '\0').collect(),
+ }
+ }
+
+ pub fn decode(&self, data: *const u8, len: usize) -> CString {
+ let txt = unsafe { std::slice::from_raw_parts(data, len) };
+ let (res, _) = self.inner.decode_with_bom_removal(txt);
+
+ match CStr::from_bytes_with_nul(res.as_bytes()) {
+ Ok(res) => CString::from(res),
+ Err(_) => {
+ // let value: String = res.chars().filter(|&c| c != '\0').collect();
+
+ let utf8_src = res.as_bytes();
+ let nul_range_end = utf8_src
+ .iter()
+ .position(|&c| c == b'\0')
+ .unwrap_or(utf8_src.len()); // default to length if no `\0` present*/
+ let data = &utf8_src[..nul_range_end];
+
+ unsafe { CString::from_vec_unchecked(data.to_vec()) }
+ }
+ }
+ }
+
+ pub fn decode_as_cow(&self, data: *const u8, len: usize) -> Cow<'static, str> {
+ let txt = unsafe { std::slice::from_raw_parts(data, len) };
+ let (res, _) = self.inner.decode_with_bom_removal(txt);
+ res
+ }
+
+ pub fn decode_c_string(&self, data: *const c_char) -> CString {
+ let txt = unsafe { CStr::from_ptr(data) };
+ let txt = txt.to_bytes();
+ let (res, _) = self.inner.decode_with_bom_removal(txt);
+
+ match CStr::from_bytes_with_nul(res.as_bytes()) {
+ Ok(res) => CString::from(res),
+ Err(_) => {
+ let value: String = res.chars().filter(|&c| c != '\0').collect();
+ CString::new(value).unwrap()
+ }
+ }
+ }
+
+ pub fn decode_as_bytes(&self, data: *const u8, len: usize) -> Vec {
+ let txt = unsafe { std::slice::from_raw_parts(data, len) };
+
+ let (res, _) = self.inner.decode_with_bom_removal(txt);
+
+ res.as_bytes().to_vec()
+ }
+
+ pub(crate) fn decode_to_bytes(&self, txt: &str) -> Vec {
+ let (res, _) = self.inner.decode_with_bom_removal(txt.as_bytes());
+
+ res.as_bytes().to_vec()
+ }
+
+ pub fn encoding(&self) -> &str {
+ self.inner.name()
+ }
+}
+
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_decoder_create(decoding: *const c_char) -> *mut TextDecoder {
+ if decoding.is_null() {
+ return std::ptr::null_mut();
+ }
+ let decoding = unsafe { CStr::from_ptr(decoding) };
+ let decoding = decoding.to_string_lossy();
+ Box::into_raw(Box::new(
+ TextDecoder::new(Some(decoding.as_ref()))
+ ))
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_decoder_decode(
+ decoder: *const TextDecoder,
+ data: *const u8,
+ size: usize,
+) -> *const c_char {
+ if decoder.is_null() || data.is_null() {
+ return std::ptr::null();
+ }
+
+ let decoder = unsafe { &*decoder };
+
+
+ decoder.decode(data, size).into_raw()
+}
+
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_decoder_decode_as_cow(
+ decoder: *const TextDecoder,
+ data: *const u8,
+ size: usize,
+) -> *mut CCow {
+ if decoder.is_null() || data.is_null() {
+ return std::ptr::null_mut();
+ }
+ let decoder = unsafe { &*decoder };
+
+ let bytes = decoder.decode_as_cow(data, size);
+
+ Box::into_raw(Box::new(CCow::from(bytes)))
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_decoder_decode_as_bytes(
+ decoder: *const TextDecoder,
+ data: *const u8,
+ size: usize,
+) -> *mut U8Buffer {
+ if decoder.is_null() || data.is_null() {
+ return std::ptr::null_mut();
+ }
+ let decoder = unsafe { &*decoder };
+
+ let bytes = decoder.decode_as_bytes(data, size);
+
+ Box::into_raw(Box::new(U8Buffer::new_with_vec(bytes)))
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_decoder_destroy(value: *mut TextDecoder) {
+ if value.is_null() {
+ return;
+ }
+ let _ = unsafe { Box::from_raw(value) };
+}
+
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_decoder_get_encoding(
+ decoder: *const TextDecoder,
+) -> *const c_char {
+ if decoder.is_null() { return std::ptr::null(); }
+ let decoder = unsafe { &*decoder };
+ CString::new(decoder.encoding().to_string().to_lowercase())
+ .unwrap()
+ .into_raw()
+}
\ No newline at end of file
diff --git a/crates/libs/nativescript-core/src/text_encoder.rs b/crates/libs/nativescript-core/src/text_encoder.rs
new file mode 100644
index 000000000..33d510bbc
--- /dev/null
+++ b/crates/libs/nativescript-core/src/text_encoder.rs
@@ -0,0 +1,82 @@
+use std::borrow::Cow;
+use std::ffi::{CStr, CString};
+use std::os::raw::c_char;
+
+use encoding_rs::UTF_8;
+
+use crate::buffers::U8Buffer;
+
+#[derive(Clone)]
+pub struct TextEncoder {
+ inner: &'static encoding_rs::Encoding,
+}
+
+impl TextEncoder {
+ pub fn new(encoding: Option<&str>) -> Self {
+ let encoding = encoding.unwrap_or("utf-8");
+ let encoder = encoding_rs::Encoding::for_label(encoding.as_bytes())
+ .unwrap_or(UTF_8.output_encoding());
+ Self { inner: encoder }
+ }
+
+ pub fn encode(&self, text: &str) -> Vec {
+ let result = self.inner.encode(text);
+ Vec::from(result.0)
+ }
+
+ pub fn encode_to_cow<'a>(&mut self, text: &'a str) -> Cow<'a, [u8]> {
+ let result = self.inner.encode(text);
+ result.0
+ }
+
+ pub fn encoding(&self) -> &str {
+ self.inner.name()
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_encoder_create(encoding: *const c_char) -> *mut TextEncoder {
+ if encoding.is_null() {
+ return std::ptr::null_mut();
+ }
+ let encoding = unsafe { CStr::from_ptr(encoding) };
+ let encoding = encoding.to_string_lossy();
+
+ Box::into_raw(Box::new(TextEncoder::new(Some(encoding.as_ref()))))
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_encoder_encode(
+ encoder: *const TextEncoder,
+ text: *const c_char,
+) -> *mut U8Buffer {
+ if encoder.is_null() || text.is_null() {
+ return std::ptr::null_mut();
+ }
+ let encoder = unsafe { &*encoder };
+ let text = unsafe { CStr::from_ptr(text) };
+ let text = text.to_string_lossy();
+ let encoded = encoder.encode(text.as_ref());
+ Box::into_raw(Box::new(U8Buffer::from(encoded)))
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_encoder_get_encoding(
+ encoder: *const TextEncoder,
+) -> *const c_char {
+ if encoder.is_null() {
+ return std::ptr::null();
+ }
+ let encoder = unsafe { &*encoder };
+ CString::new(encoder.encoding().to_string().to_lowercase())
+ .unwrap()
+ .into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_text_encoder_destroy(value: *mut TextEncoder) {
+ if value.is_null() {
+ return;
+ }
+ let _ = unsafe { Box::from_raw(value) };
+}
diff --git a/crates/libs/nativescript-core/src/url.rs b/crates/libs/nativescript-core/src/url.rs
new file mode 100644
index 000000000..c64388b1d
--- /dev/null
+++ b/crates/libs/nativescript-core/src/url.rs
@@ -0,0 +1,392 @@
+use std::ffi::{c_char, CStr, CString};
+
+use ada_url::Url;
+
+use crate::ccow::CCow;
+
+pub struct URL(Url);
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_can_parse(value: *const c_char, base: *const c_char) -> bool {
+ let value_null = value.is_null();
+ let base_null = base.is_null();
+ if value_null && base_null {
+ return false;
+ }
+
+ if value_null {
+ let base = unsafe { CStr::from_ptr(base) };
+ let base = base.to_string_lossy();
+
+ return Url::can_parse("", Some(base.as_ref()));
+ }
+
+ let value = unsafe { CStr::from_ptr(value) };
+ let value = value.to_string_lossy();
+
+ if base_null {
+ return Url::can_parse(value.as_ref(), None);
+ }
+
+ let base = unsafe { CStr::from_ptr(base) };
+ let base = base.to_string_lossy();
+
+ Url::can_parse(value.as_ref(), Some(base.as_ref()))
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_create(value: *const c_char, base: *const c_char) -> *mut URL {
+ let value = unsafe { CStr::from_ptr(value) };
+ let value = value.to_string_lossy();
+
+ let url = if base.is_null() {
+ Url::parse(value, None)
+ } else {
+ let base = unsafe { CStr::from_ptr(base) };
+ let base = base.to_string_lossy();
+ Url::parse(value, Some(base.as_ref()))
+ };
+
+ // todo return error
+ match url {
+ Ok(url) => Box::into_raw(Box::new(URL(url))),
+ Err(_) => std::ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_destroy(url: *mut URL) {
+ if !url.is_null() {
+ let _ = unsafe { Box::from_raw(url) };
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_to_string(url: *mut URL) -> *mut CCow {
+ if url.is_null() {
+ return std::ptr::null_mut();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ Box::into_raw(Box::new(CCow::from(url.to_string())))
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_hash(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.hash()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_hash(url: *mut URL, hash: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if hash.is_null() {
+ url.set_hash(None);
+ } else {
+ let hash = unsafe { CStr::from_ptr(hash) };
+ let hash = hash.to_string_lossy();
+
+ url.set_hash(Some(hash.as_ref()));
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_host(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.host()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_host(url: *mut URL, host: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if host.is_null() {
+ let _ = url.set_host(None);
+ } else {
+ let host = unsafe { CStr::from_ptr(host) };
+ let host = host.to_string_lossy();
+
+ let _ = url.set_host(Some(host.as_ref()));
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_host_name(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.hostname()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_host_name(url: *mut URL, hostname: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if hostname.is_null() {
+ let _ = url.set_hostname(None);
+ } else {
+ let hostname = unsafe { CStr::from_ptr(hostname) };
+ let hostname = hostname.to_string_lossy();
+
+ let _ = url.set_hostname(Some(hostname.as_ref()));
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_href(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.href()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_href(url: *mut URL, href: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if !href.is_null() {
+ let href = unsafe { CStr::from_ptr(href) };
+ let href = href.to_string_lossy();
+
+ let _ = url.set_href(href.as_ref());
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_origin(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.origin()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_password(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.password()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_password(url: *mut URL, password: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if password.is_null() {
+ let _ = url.set_password(None);
+ } else {
+ let password = unsafe { CStr::from_ptr(password) };
+ let password = password.to_string_lossy();
+
+ let _ = url.set_password(Some(password.as_ref()));
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_pathname(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.pathname()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_pathname(url: *mut URL, pathname: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if pathname.is_null() {
+ let _ = url.set_pathname(None);
+ } else {
+ let pathname = unsafe { CStr::from_ptr(pathname) };
+ let pathname = pathname.to_string_lossy();
+
+ let _ = url.set_pathname(Some(pathname.as_ref()));
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_port(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.port()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_port(url: *mut URL, port: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if port.is_null() {
+ let _ = url.set_port(None);
+ } else {
+ let port = unsafe { CStr::from_ptr(port) };
+ let port = port.to_string_lossy();
+
+ let _ = url.set_port(Some(port.as_ref()));
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_protocol(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.protocol()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_protocol(url: *mut URL, protocol: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if !protocol.is_null() {
+ let protocol = unsafe { CStr::from_ptr(protocol) };
+ let protocol = protocol.to_string_lossy();
+
+ let _ = url.set_protocol(protocol.as_ref());
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_search(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.search()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_search(url: *mut URL, search: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if search.is_null() {
+ let _ = url.set_search(None);
+ } else {
+ let search = unsafe { CStr::from_ptr(search) };
+ let search = search.to_string_lossy();
+
+ let _ = url.set_search(Some(search.as_ref()));
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_username(url: *mut URL) -> *const c_char {
+ if url.is_null() {
+ return std::ptr::null();
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ CString::new(url.username()).unwrap().into_raw()
+}
+
+#[no_mangle]
+pub extern "C" fn nativescript_core_url_set_username(url: *mut URL, username: *const c_char) {
+ if url.is_null() {
+ return;
+ }
+
+ let url = unsafe { &mut *url };
+ let url = &mut url.0;
+
+ if username.is_null() {
+ let _ = url.set_username(None);
+ } else {
+ let username = unsafe { CStr::from_ptr(username) };
+ let username = username.to_string_lossy();
+
+ let _ = url.set_username(Some(username.as_ref()));
+ }
+}
\ No newline at end of file
diff --git a/packages/core/globals/index.ts b/packages/core/globals/index.ts
index 5352d79fb..f804d437d 100644
--- a/packages/core/globals/index.ts
+++ b/packages/core/globals/index.ts
@@ -311,7 +311,7 @@ export function initGlobal() {
installPolyfills('ui-dialogs', ['alert', 'confirm', 'prompt', 'login', 'action']);
global.registerModule('text', () => require('../text'));
- installPolyfills('text', ['TextDecoder', 'TextEncoder']);
+ installPolyfills('text', ['TextDecoder', 'TextEncoder', 'atob', 'btoa']);
global.registerModule('xhr', () => require('../xhr'));
installPolyfills('xhr', ['XMLHttpRequest', 'FormData', 'Blob', 'File', 'FileReader']);
@@ -319,6 +319,9 @@ export function initGlobal() {
global.registerModule('fetch', () => require('../fetch'));
installPolyfills('fetch', ['fetch', 'Headers', 'Request', 'Response']);
+ global.registerModule('url', () => require('../url'));
+ installPolyfills('url', ['URL']);
+
// global.registerModule('abortcontroller', () => require('../abortcontroller'));
// installPolyfills('abortcontroller', ['AbortController', 'AbortSignal']);
diff --git a/packages/core/native-helpers.ts b/packages/core/native-helpers.ts
new file mode 100644
index 000000000..0274107b3
--- /dev/null
+++ b/packages/core/native-helpers.ts
@@ -0,0 +1,14 @@
+declare const __non_webpack_require__;
+
+if (global.isAndroid) {
+ try {
+ __non_webpack_require__('system_lib://libnativescriptcorev8.so');
+ } catch (error) {}
+}
+
+if (global.isIOS) {
+ try {
+ const installer = global.NativeScriptCoreModuleInstaller.new();
+ installer.install();
+ } catch (error) {}
+}
diff --git a/packages/core/platforms/android/include.gradle b/packages/core/platforms/android/include.gradle
new file mode 100644
index 000000000..5a16150dc
--- /dev/null
+++ b/packages/core/platforms/android/include.gradle
@@ -0,0 +1,8 @@
+android {
+ packagingOptions {
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
+ pickFirst 'lib/x86_64/libc++_shared.so'
+ pickFirst 'lib/x86/libc++_shared.so'
+ }
+}
\ No newline at end of file
diff --git a/packages/core/platforms/android/widgets-release.aar b/packages/core/platforms/android/widgets-release.aar
index 87cbccb7e..95e9bf77d 100644
Binary files a/packages/core/platforms/android/widgets-release.aar and b/packages/core/platforms/android/widgets-release.aar differ
diff --git a/packages/core/platforms/ios/NativeScriptCore.xcframework/Info.plist b/packages/core/platforms/ios/NativeScriptCore.xcframework/Info.plist
new file mode 100644
index 000000000..b0febf923
--- /dev/null
+++ b/packages/core/platforms/ios/NativeScriptCore.xcframework/Info.plist
@@ -0,0 +1,44 @@
+
+
+
+
+ AvailableLibraries
+
+
+ HeadersPath
+ Headers
+ LibraryIdentifier
+ ios-arm64_x86_64-simulator
+ LibraryPath
+ libnativescriptcore.dylib
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ HeadersPath
+ Headers
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ libnativescriptcore.dylib
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64/Headers/nativescript_core.h b/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64/Headers/nativescript_core.h
new file mode 100644
index 000000000..fb2148370
--- /dev/null
+++ b/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64/Headers/nativescript_core.h
@@ -0,0 +1,171 @@
+#ifndef CBINDGEN_BINDINGS_H
+#define CBINDGEN_BINDINGS_H
+
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#include
+#include
+#include
+#include
+
+typedef struct CCow CCow;
+
+typedef struct F32Buffer F32Buffer;
+
+typedef struct I32Buffer I32Buffer;
+
+typedef struct StringBuffer StringBuffer;
+
+typedef struct TextDecoder TextDecoder;
+
+typedef struct TextEncoder TextEncoder;
+
+typedef struct U16Buffer U16Buffer;
+
+typedef struct U32Buffer U32Buffer;
+
+typedef struct U8Buffer U8Buffer;
+
+typedef struct URL URL;
+
+struct U8Buffer *nativescript_core_atob(const char *value);
+
+struct U8Buffer *nativescript_core_atob_ccow(const struct CCow *value);
+
+struct CCow *nativescript_core_btoa(const char *value);
+
+struct CCow *nativescript_core_btoa_ccow(const struct CCow *value);
+
+void nativescript_core_string_destroy(char *value);
+
+bool nativescript_core_url_can_parse(const char *value, const char *base);
+
+struct URL *nativescript_core_url_create(const char *value, const char *base);
+
+void nativescript_core_url_destroy(struct URL *url);
+
+struct CCow *nativescript_core_url_to_string(struct URL *url);
+
+const char *nativescript_core_url_hash(struct URL *url);
+
+void nativescript_core_url_set_hash(struct URL *url, const char *hash);
+
+const char *nativescript_core_url_host(struct URL *url);
+
+void nativescript_core_url_set_host(struct URL *url, const char *host);
+
+const char *nativescript_core_url_host_name(struct URL *url);
+
+void nativescript_core_url_set_host_name(struct URL *url, const char *hostname);
+
+const char *nativescript_core_url_href(struct URL *url);
+
+void nativescript_core_url_set_href(struct URL *url, const char *href);
+
+const char *nativescript_core_url_origin(struct URL *url);
+
+const char *nativescript_core_url_password(struct URL *url);
+
+void nativescript_core_url_set_password(struct URL *url, const char *password);
+
+const char *nativescript_core_url_pathname(struct URL *url);
+
+void nativescript_core_url_set_pathname(struct URL *url, const char *pathname);
+
+const char *nativescript_core_url_port(struct URL *url);
+
+void nativescript_core_url_set_port(struct URL *url, const char *port);
+
+const char *nativescript_core_url_protocol(struct URL *url);
+
+void nativescript_core_url_set_protocol(struct URL *url, const char *protocol);
+
+const char *nativescript_core_url_search(struct URL *url);
+
+void nativescript_core_url_set_search(struct URL *url, const char *search);
+
+const char *nativescript_core_url_username(struct URL *url);
+
+void nativescript_core_url_set_username(struct URL *url, const char *username);
+
+void nativescript_core_ccow_destroy(struct CCow *cow);
+
+const uint8_t *nativescript_core_ccow_get_bytes(const struct CCow *cow);
+
+uintptr_t nativescript_core_ccow_get_length(const struct CCow *cow);
+
+struct TextDecoder *nativescript_core_text_decoder_create(const char *decoding);
+
+const char *nativescript_core_text_decoder_decode(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+struct CCow *nativescript_core_text_decoder_decode_as_cow(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+struct U8Buffer *nativescript_core_text_decoder_decode_as_bytes(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+void nativescript_core_text_decoder_destroy(struct TextDecoder *value);
+
+const char *nativescript_core_text_decoder_get_encoding(const struct TextDecoder *decoder);
+
+struct TextEncoder *nativescript_core_text_encoder_create(const char *encoding);
+
+struct U8Buffer *nativescript_core_text_encoder_encode(const struct TextEncoder *encoder,
+ const char *text);
+
+const char *nativescript_core_text_encoder_get_encoding(const struct TextEncoder *encoder);
+
+void nativescript_core_text_encoder_destroy(struct TextEncoder *value);
+
+const uint8_t *nativescript_core_u8_buffer_get_bytes(const struct U8Buffer *buffer);
+
+uint8_t *nativescript_core_u8_buffer_get_bytes_mut(struct U8Buffer *buffer);
+
+void nativescript_core_u8_buffer_destroy(struct U8Buffer *buffer);
+
+uintptr_t nativescript_core_u8_buffer_get_length(const struct U8Buffer *buffer);
+
+const uint16_t *nativescript_core_u16_buffer_get_bytes(const struct U16Buffer *buffer);
+
+uint16_t *nativescript_core_u16_buffer_get_bytes_mut(struct U16Buffer *buffer);
+
+void nativescript_core_u16_buffer_destroy(struct U16Buffer *buffer);
+
+uintptr_t nativescript_core_u16_buffer_get_length(const struct U16Buffer *buffer);
+
+const uint32_t *nativescript_core_u32_buffer_get_bytes(const struct U32Buffer *buffer);
+
+uint32_t *nativescript_core_u32_buffer_get_bytes_mut(struct U32Buffer *buffer);
+
+void nativescript_core_u32_buffer_destroy(struct U32Buffer *buffer);
+
+uintptr_t nativescript_core_u32_buffer_get_length(const struct U32Buffer *buffer);
+
+const int32_t *nativescript_core_i32_buffer_get_bytes(const struct I32Buffer *buffer);
+
+int32_t *nativescript_core_i32_buffer_get_bytes_mut(struct I32Buffer *buffer);
+
+void nativescript_core_i32_buffer_destroy(struct I32Buffer *buffer);
+
+uintptr_t nativescript_core_i32_buffer_get_length(const struct I32Buffer *buffer);
+
+const float *nativescript_core_f32_buffer_get_bytes(const struct F32Buffer *buffer);
+
+float *nativescript_core_f32_buffer_get_bytes_mut(struct F32Buffer *buffer);
+
+void nativescript_core_f32_buffer_destroy(struct F32Buffer *buffer);
+
+uintptr_t nativescript_core_f32_buffer_get_length(const struct F32Buffer *buffer);
+
+uintptr_t nativescript_core_string_buffer_get_length(const struct StringBuffer *buffer);
+
+char *nativescript_core_string_buffer_get_value_at(const struct StringBuffer *buffer,
+ uintptr_t index);
+
+void nativescript_core_string_buffer_destroy(struct StringBuffer *buffer);
+
+#endif /* CBINDGEN_BINDINGS_H */
diff --git a/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64/libnativescriptcore.dylib b/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64/libnativescriptcore.dylib
new file mode 100755
index 000000000..e3773c53e
Binary files /dev/null and b/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64/libnativescriptcore.dylib differ
diff --git a/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64_x86_64-simulator/Headers/nativescript_core.h b/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64_x86_64-simulator/Headers/nativescript_core.h
new file mode 100644
index 000000000..fb2148370
--- /dev/null
+++ b/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64_x86_64-simulator/Headers/nativescript_core.h
@@ -0,0 +1,171 @@
+#ifndef CBINDGEN_BINDINGS_H
+#define CBINDGEN_BINDINGS_H
+
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#include
+#include
+#include
+#include
+
+typedef struct CCow CCow;
+
+typedef struct F32Buffer F32Buffer;
+
+typedef struct I32Buffer I32Buffer;
+
+typedef struct StringBuffer StringBuffer;
+
+typedef struct TextDecoder TextDecoder;
+
+typedef struct TextEncoder TextEncoder;
+
+typedef struct U16Buffer U16Buffer;
+
+typedef struct U32Buffer U32Buffer;
+
+typedef struct U8Buffer U8Buffer;
+
+typedef struct URL URL;
+
+struct U8Buffer *nativescript_core_atob(const char *value);
+
+struct U8Buffer *nativescript_core_atob_ccow(const struct CCow *value);
+
+struct CCow *nativescript_core_btoa(const char *value);
+
+struct CCow *nativescript_core_btoa_ccow(const struct CCow *value);
+
+void nativescript_core_string_destroy(char *value);
+
+bool nativescript_core_url_can_parse(const char *value, const char *base);
+
+struct URL *nativescript_core_url_create(const char *value, const char *base);
+
+void nativescript_core_url_destroy(struct URL *url);
+
+struct CCow *nativescript_core_url_to_string(struct URL *url);
+
+const char *nativescript_core_url_hash(struct URL *url);
+
+void nativescript_core_url_set_hash(struct URL *url, const char *hash);
+
+const char *nativescript_core_url_host(struct URL *url);
+
+void nativescript_core_url_set_host(struct URL *url, const char *host);
+
+const char *nativescript_core_url_host_name(struct URL *url);
+
+void nativescript_core_url_set_host_name(struct URL *url, const char *hostname);
+
+const char *nativescript_core_url_href(struct URL *url);
+
+void nativescript_core_url_set_href(struct URL *url, const char *href);
+
+const char *nativescript_core_url_origin(struct URL *url);
+
+const char *nativescript_core_url_password(struct URL *url);
+
+void nativescript_core_url_set_password(struct URL *url, const char *password);
+
+const char *nativescript_core_url_pathname(struct URL *url);
+
+void nativescript_core_url_set_pathname(struct URL *url, const char *pathname);
+
+const char *nativescript_core_url_port(struct URL *url);
+
+void nativescript_core_url_set_port(struct URL *url, const char *port);
+
+const char *nativescript_core_url_protocol(struct URL *url);
+
+void nativescript_core_url_set_protocol(struct URL *url, const char *protocol);
+
+const char *nativescript_core_url_search(struct URL *url);
+
+void nativescript_core_url_set_search(struct URL *url, const char *search);
+
+const char *nativescript_core_url_username(struct URL *url);
+
+void nativescript_core_url_set_username(struct URL *url, const char *username);
+
+void nativescript_core_ccow_destroy(struct CCow *cow);
+
+const uint8_t *nativescript_core_ccow_get_bytes(const struct CCow *cow);
+
+uintptr_t nativescript_core_ccow_get_length(const struct CCow *cow);
+
+struct TextDecoder *nativescript_core_text_decoder_create(const char *decoding);
+
+const char *nativescript_core_text_decoder_decode(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+struct CCow *nativescript_core_text_decoder_decode_as_cow(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+struct U8Buffer *nativescript_core_text_decoder_decode_as_bytes(const struct TextDecoder *decoder,
+ const uint8_t *data,
+ uintptr_t size);
+
+void nativescript_core_text_decoder_destroy(struct TextDecoder *value);
+
+const char *nativescript_core_text_decoder_get_encoding(const struct TextDecoder *decoder);
+
+struct TextEncoder *nativescript_core_text_encoder_create(const char *encoding);
+
+struct U8Buffer *nativescript_core_text_encoder_encode(const struct TextEncoder *encoder,
+ const char *text);
+
+const char *nativescript_core_text_encoder_get_encoding(const struct TextEncoder *encoder);
+
+void nativescript_core_text_encoder_destroy(struct TextEncoder *value);
+
+const uint8_t *nativescript_core_u8_buffer_get_bytes(const struct U8Buffer *buffer);
+
+uint8_t *nativescript_core_u8_buffer_get_bytes_mut(struct U8Buffer *buffer);
+
+void nativescript_core_u8_buffer_destroy(struct U8Buffer *buffer);
+
+uintptr_t nativescript_core_u8_buffer_get_length(const struct U8Buffer *buffer);
+
+const uint16_t *nativescript_core_u16_buffer_get_bytes(const struct U16Buffer *buffer);
+
+uint16_t *nativescript_core_u16_buffer_get_bytes_mut(struct U16Buffer *buffer);
+
+void nativescript_core_u16_buffer_destroy(struct U16Buffer *buffer);
+
+uintptr_t nativescript_core_u16_buffer_get_length(const struct U16Buffer *buffer);
+
+const uint32_t *nativescript_core_u32_buffer_get_bytes(const struct U32Buffer *buffer);
+
+uint32_t *nativescript_core_u32_buffer_get_bytes_mut(struct U32Buffer *buffer);
+
+void nativescript_core_u32_buffer_destroy(struct U32Buffer *buffer);
+
+uintptr_t nativescript_core_u32_buffer_get_length(const struct U32Buffer *buffer);
+
+const int32_t *nativescript_core_i32_buffer_get_bytes(const struct I32Buffer *buffer);
+
+int32_t *nativescript_core_i32_buffer_get_bytes_mut(struct I32Buffer *buffer);
+
+void nativescript_core_i32_buffer_destroy(struct I32Buffer *buffer);
+
+uintptr_t nativescript_core_i32_buffer_get_length(const struct I32Buffer *buffer);
+
+const float *nativescript_core_f32_buffer_get_bytes(const struct F32Buffer *buffer);
+
+float *nativescript_core_f32_buffer_get_bytes_mut(struct F32Buffer *buffer);
+
+void nativescript_core_f32_buffer_destroy(struct F32Buffer *buffer);
+
+uintptr_t nativescript_core_f32_buffer_get_length(const struct F32Buffer *buffer);
+
+uintptr_t nativescript_core_string_buffer_get_length(const struct StringBuffer *buffer);
+
+char *nativescript_core_string_buffer_get_value_at(const struct StringBuffer *buffer,
+ uintptr_t index);
+
+void nativescript_core_string_buffer_destroy(struct StringBuffer *buffer);
+
+#endif /* CBINDGEN_BINDINGS_H */
diff --git a/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64_x86_64-simulator/libnativescriptcore.dylib b/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64_x86_64-simulator/libnativescriptcore.dylib
new file mode 100755
index 000000000..4aa172b3f
Binary files /dev/null and b/packages/core/platforms/ios/NativeScriptCore.xcframework/ios-arm64_x86_64-simulator/libnativescriptcore.dylib differ
diff --git a/packages/core/platforms/ios/Podfile b/packages/core/platforms/ios/Podfile
new file mode 100644
index 000000000..14a4dbf1b
--- /dev/null
+++ b/packages/core/platforms/ios/Podfile
@@ -0,0 +1,2 @@
+# Exposes NativeScript v8 headers to our module sources
+pod 'NativeScript', path: "../../node_modules/@nativescript/core/src-native/ios/NativeScript.podspec"
\ No newline at end of file
diff --git a/packages/core/platforms/ios/build.xcconfig b/packages/core/platforms/ios/build.xcconfig
new file mode 100644
index 000000000..b8de40819
--- /dev/null
+++ b/packages/core/platforms/ios/build.xcconfig
@@ -0,0 +1,3 @@
+HEADER_SEARCH_PATHS = $(inherited) "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/NativeScript.framework/Headers" "$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/NativeScript.framework/Headers/include"
+
+CLANG_CXX_LANGUAGE_STANDARD = c++17
\ No newline at end of file
diff --git a/packages/core/platforms/ios/src/NativeScriptCoreModuleInstaller.h b/packages/core/platforms/ios/src/NativeScriptCoreModuleInstaller.h
new file mode 100644
index 000000000..2ca6faca0
--- /dev/null
+++ b/packages/core/platforms/ios/src/NativeScriptCoreModuleInstaller.h
@@ -0,0 +1,7 @@
+#import
+
+@interface NativeScriptCoreModuleInstaller : NSObject
+
+- (void) install;
+
+@end
diff --git a/packages/core/platforms/ios/src/NativeScriptCoreModuleInstaller.mm b/packages/core/platforms/ios/src/NativeScriptCoreModuleInstaller.mm
new file mode 100644
index 000000000..55cdeac86
--- /dev/null
+++ b/packages/core/platforms/ios/src/NativeScriptCoreModuleInstaller.mm
@@ -0,0 +1,14 @@
+#import "NativeScriptCoreModuleInstaller.h"
+#import
+#import "CoreJSIModule.h"
+
+using namespace std;
+
+@implementation NativeScriptCoreModuleInstaller
+
+- (void )install {
+ v8::Isolate* isolate = tns::Runtime::GetCurrentRuntime()->GetIsolate();
+ CoreJSIModule::install(isolate);
+}
+
+@end
diff --git a/packages/core/platforms/ios/src/cpp/Caches.cpp b/packages/core/platforms/ios/src/cpp/Caches.cpp
new file mode 100644
index 000000000..6890c0bbb
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/Caches.cpp
@@ -0,0 +1,35 @@
+//
+// Created by Osei Fortune on 10/06/2022.
+//
+
+#include "Caches.h"
+
+std::shared_ptr >>
+Caches::perIsolateCaches_ = std::make_shared < ConcurrentMap>
+>();
+
+Caches::Caches(v8::Isolate *isolate) : isolate_(isolate) {}
+
+Caches::~Caches() {}
+
+std::shared_ptr Caches::Get(v8::Isolate *isolate) {
+ std::shared_ptr cache = Caches::perIsolateCaches_->Get(isolate);
+ if (cache == nullptr) {
+ cache = std::make_shared(isolate);
+ Caches::perIsolateCaches_->Insert(isolate, cache);
+ }
+
+ return cache;
+}
+
+void Caches::Remove(v8::Isolate *isolate) {
+ Caches::perIsolateCaches_->Remove(isolate);
+}
+
+void Caches::SetContext(v8::Local context) {
+ this->context_ = std::make_shared>(this->isolate_, context);
+}
+
+v8::Local Caches::GetContext() {
+ return this->context_->Get(this->isolate_);
+}
diff --git a/packages/core/platforms/ios/src/cpp/Caches.h b/packages/core/platforms/ios/src/cpp/Caches.h
new file mode 100644
index 000000000..ef1079d67
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/Caches.h
@@ -0,0 +1,40 @@
+//
+// Created by Osei Fortune on 10/06/2022.
+//
+
+#pragma once
+
+#include "Common.h"
+#include "ConcurrentMap.h"
+
+class Caches {
+public:
+ Caches(v8::Isolate *isolate);
+
+ ~Caches();
+
+ static std::shared_ptr Get(v8::Isolate *isolate);
+
+ static void Remove(v8::Isolate *isolate);
+
+ void SetContext(v8::Local context);
+
+ v8::Local GetContext();
+
+ std::unique_ptr> TextDecoderTmpl = std::unique_ptr>(
+ nullptr);
+
+ std::unique_ptr> TextEncoderTmpl = std::unique_ptr>(
+ nullptr);
+
+ std::unique_ptr> URLTmpl = std::unique_ptr>(
+ nullptr);
+
+
+private:
+ static std::shared_ptr>>
+ perIsolateCaches_;
+ v8::Isolate *isolate_;
+ std::shared_ptr> context_;
+};
diff --git a/packages/core/platforms/ios/src/cpp/Common.h b/packages/core/platforms/ios/src/cpp/Common.h
new file mode 100644
index 000000000..4c2205817
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/Common.h
@@ -0,0 +1,29 @@
+//
+// Created by Osei Fortune on 10/06/2022.
+//
+
+#pragma once
+#include
+#include
+
+#ifdef __APPLE__
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "include/nativescript_core.h"
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+#ifdef __ANDROID__
+#include "include/v8.h"
+extern "C" {
+#include "include/nativescript_core.h"
+}
+#include
+#include
+#endif
+
diff --git a/packages/core/platforms/ios/src/cpp/ConcurrentMap.h b/packages/core/platforms/ios/src/cpp/ConcurrentMap.h
new file mode 100644
index 000000000..565b8a5d2
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/ConcurrentMap.h
@@ -0,0 +1,54 @@
+//
+// Created by Osei Fortune on 10/06/2022.
+//
+
+#pragma once
+
+#include
+#include "include/robin_hood.h"
+template
+class ConcurrentMap {
+public:
+ void Insert(TKey &key, TValue value) {
+ std::lock_guard writerLock(this->containerMutex_);
+ this->container_[key] = value;
+ }
+
+ TValue Get(TKey &key) {
+ bool found;
+ return this->Get(key, found);
+ }
+
+ TValue Get(TKey &key, bool &found) {
+// std::shared_lock readerLock(this->containerMutex_);
+ std::lock_guard writerLock(this->containerMutex_);
+ auto it = this->container_.find(key);
+ found = it != this->container_.end();
+ if (found) {
+ return it->second;
+ }
+ return nullptr;
+ }
+
+ bool ContainsKey(TKey &key) {
+// std::shared_lock readerLock(this->containerMutex_);
+ std::lock_guard writerLock(this->containerMutex_);
+ auto it = this->container_.find(key);
+ return it != this->container_.end();
+ }
+
+ void Remove(TKey &key) {
+ std::lock_guard writerLock(this->containerMutex_);
+ this->container_.erase(key);
+ }
+
+ ConcurrentMap() = default;
+
+ ConcurrentMap(const ConcurrentMap &) = delete;
+
+ ConcurrentMap &operator=(const ConcurrentMap &) = delete;
+
+private:
+ std::mutex containerMutex_;
+ robin_hood::unordered_map container_;
+};
diff --git a/packages/core/platforms/ios/src/cpp/CoreJSIModule.cpp b/packages/core/platforms/ios/src/cpp/CoreJSIModule.cpp
new file mode 100644
index 000000000..cf6a974ea
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/CoreJSIModule.cpp
@@ -0,0 +1,57 @@
+//
+// Created by Osei Fortune on 25/02/2023.
+//
+
+#include "CoreJSIModule.h"
+#include "Helpers.h"
+
+void CoreJSIModule::install(v8::Isolate *isolate) {
+
+ auto context = isolate->GetCurrentContext();
+ auto global = context->Global();
+
+ if (!global->
+ HasOwnProperty(context, ConvertToV8String(isolate, "NativeScriptCoreModule")).FromMaybe(
+ false)) {
+
+
+ v8::Locker locker(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope(isolate);
+
+
+ auto coreMod = v8::Object::New(isolate);
+ TextDecoderImpl::Init(coreMod, isolate);
+ TextEncoderImpl::Init(coreMod, isolate);
+ URLImpl::Init(coreMod, isolate);
+
+ coreMod->Set(context, ConvertToV8String(isolate, "atob"),
+ v8::FunctionTemplate::New(isolate, &Atob)->GetFunction(
+ context).ToLocalChecked());
+ coreMod->Set(context, ConvertToV8String(isolate, "btoa"),
+ v8::FunctionTemplate::New(isolate, &Btoa)->GetFunction(
+ context).ToLocalChecked());
+
+ global->Set(context,
+ ConvertToV8String(isolate, "NativeScriptCoreModule"), coreMod);
+
+ }
+}
+
+void CoreJSIModule::Atob(const v8::FunctionCallbackInfo &args) {
+ auto isolate = args.GetIsolate();
+ auto value = args[0];
+ auto string = ConvertFromV8String(isolate, value);
+ auto buffer = nativescript_core_atob(string.c_str());
+ auto returnValue = new OneByteStringResource(buffer);
+ auto ret = v8::String::NewExternalOneByte(isolate, returnValue);
+ args.GetReturnValue().Set(ret.ToLocalChecked());
+}
+
+void CoreJSIModule::Btoa(const v8::FunctionCallbackInfo &args) {
+ auto isolate = args.GetIsolate();
+ auto value = ConvertFromV8String(isolate, args[0]);
+ auto returnValue = new OneByteStringResource(nativescript_core_btoa(value.c_str()));
+ auto ret = v8::String::NewExternalOneByte(isolate, returnValue);
+ args.GetReturnValue().Set(ret.ToLocalChecked());
+}
diff --git a/packages/core/platforms/ios/src/cpp/CoreJSIModule.h b/packages/core/platforms/ios/src/cpp/CoreJSIModule.h
new file mode 100644
index 000000000..adc1d0a51
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/CoreJSIModule.h
@@ -0,0 +1,24 @@
+//
+// Created by Osei Fortune on 25/02/2023.
+//
+
+#pragma once
+
+#include
+#include
+#include "Helpers.h"
+
+#include "TextDecoderImpl.h"
+#include "TextEncoderImpl.h"
+
+#include "URLImpl.h"
+
+class CoreJSIModule {
+public:
+ static void install(v8::Isolate *isolate);
+
+ static void Atob(const v8::FunctionCallbackInfo &args);
+
+ static void Btoa(const v8::FunctionCallbackInfo &args);
+};
+
diff --git a/packages/core/platforms/ios/src/cpp/Helpers.h b/packages/core/platforms/ios/src/cpp/Helpers.h
new file mode 100644
index 000000000..3a0e43de7
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/Helpers.h
@@ -0,0 +1,329 @@
+//
+// Created by Osei Fortune on 25/02/2023.
+//
+
+#pragma once
+
+#include
+#include "Common.h"
+#include "OneByteStringResource.h"
+
+//#ifdef __APPLE__
+//#ifdef __OBJC__
+//#include
+//#else
+//#include
+//extern "C" void NSLog(CFStringRef format, ...);
+//#endif
+//#endif
+
+
+
+static const char *LOG_TAG = "JS";
+static int m_maxLogcatObjectSize = 4096;
+
+#ifdef __ANDROID__
+static void sendToADBLogcat(const std::string &message, android_LogPriority logPriority) {
+ // limit the size of the message that we send to logcat using the predefined value in package.json
+ auto messageToLog = message;
+ if (messageToLog.length() > m_maxLogcatObjectSize) {
+ messageToLog = messageToLog.erase(m_maxLogcatObjectSize, std::string::npos);
+ messageToLog = messageToLog + "...";
+ }
+
+ // split strings into chunks of 4000 characters
+ // __android_log_write can't send more than 4000 to the stdout at a time
+ auto messageLength = messageToLog.length();
+ int maxStringLength = 4000;
+
+ if (messageLength < maxStringLength) {
+ __android_log_write(logPriority, LOG_TAG, messageToLog.c_str());
+ } else {
+ for (int i = 0; i < messageLength; i += maxStringLength) {
+ auto messagePart = messageToLog.substr(i, maxStringLength);
+
+ __android_log_write(logPriority, LOG_TAG, messagePart.c_str());
+ }
+ }
+}
+#endif
+
+//#ifdef __APPLE__
+//#ifndef __OBJC__
+//#define Log(fmt, ...) NSLog(CFSTR(fmt), ##__VA_ARGS__)
+//#else
+//#define Log(...) NSLog(__VA_ARGS__)
+//#endif
+//#endif
+
+
+
+static void LogToConsole(const std::string &message) {
+#ifdef __ANDROID__
+ sendToADBLogcat(message, android_LogPriority::ANDROID_LOG_INFO);
+#endif
+
+#ifdef __APPLE__
+ // Log("%s", message.c_str());
+#endif
+}
+
+
+
+enum class NativeType {
+ None,
+ CanvasGradient,
+ CanvasPattern,
+ ImageData,
+ ImageAsset,
+ CanvasRenderingContext2D,
+ WebGLRenderingContextBase,
+ Path2D,
+ Matrix,
+ ImageBitmap,
+ TextMetrics,
+
+ WebGLQuery,
+ WebGLProgram,
+ WebGLShader,
+ WebGLBuffer,
+ WebGLFramebuffer,
+ WebGLRenderbuffer,
+ WebGLTexture,
+ WebGLActiveInfo,
+ OES_fbo_render_mipmap,
+ EXT_blend_minmax,
+ EXT_color_buffer_half_float,
+ EXT_disjoint_timer_query,
+ EXT_sRGB,
+ EXT_shader_texture_lod,
+ EXT_texture_filter_anisotropic,
+ OES_element_index_uint,
+ OES_standard_derivatives,
+ OES_texture_float,
+ OES_texture_float_linear,
+ OES_texture_half_float_linear,
+ OES_texture_half_float,
+ WEBGL_color_buffer_float,
+ OES_vertex_array_object,
+ WebGLVertexArrayObject,
+ WEBGL_compressed_texture_atc,
+ WEBGL_compressed_texture_etc1,
+ WEBGL_compressed_texture_s3tc,
+ WEBGL_compressed_texture_s3tc_srgb,
+ WEBGL_compressed_texture_etc,
+ WEBGL_compressed_texture_pvrtc,
+ WEBGL_lose_context,
+ ANGLE_instanced_arrays,
+ WEBGL_depth_texture,
+ WEBGL_draw_buffers,
+ WebGLShaderPrecisionFormat,
+ WebGLUniformLocation,
+ WebGLSampler,
+ WebGLTransformFeedback,
+ WebGLSync
+};
+
+
+inline static v8::Local
+ConvertToV8OneByteString(v8::Isolate *isolate, char* string) {
+ auto value = new OneByteStringResource(string);
+ auto ret = v8::String::NewExternalOneByte(isolate, value);
+ return ret.ToLocalChecked();
+}
+
+inline static v8::Local
+ConvertToV8String(v8::Isolate *isolate, const std::string &string) {
+ return v8::String::NewFromUtf8(isolate, string.c_str()).ToLocalChecked();
+}
+
+inline static std::string
+ConvertFromV8String(v8::Isolate *isolate, const v8::Local &value) {
+ if (value.IsEmpty()) {
+ return {};
+ }
+
+ if (value->IsStringObject()) {
+ v8::Local obj = value.As()->ValueOf();
+ return ConvertFromV8String(isolate, obj);
+ }
+
+ v8::String::Utf8Value result(isolate, value);
+
+ const char *val = *result;
+
+ if (val == nullptr) {
+ return {};
+ }
+
+ return {*result};
+}
+
+
+static void SetPrivateValue(v8::Isolate *isolate, const v8::Local &obj,
+ const v8::Local &propName,
+ const v8::Local &value) {
+ v8::Local context;
+ obj->GetCreationContext().ToLocal(&context);
+ v8::Local privateKey = v8::Private::ForApi(isolate, propName);
+ obj->SetPrivate(context, privateKey, value);
+}
+
+static v8::Local
+GetPrivateValue(v8::Isolate *isolate, const v8::Local &obj,
+ const v8::Local &propName) {
+ v8::Local context;
+ obj->GetCreationContext().ToLocal(&context);
+ v8::Local privateKey = v8::Private::ForApi(isolate, propName);
+
+ v8::Maybe hasPrivate = obj->HasPrivate(context, privateKey);
+
+ if (!hasPrivate.FromMaybe(false)) {
+ return v8::Local();
+ }
+
+ v8::Local result;
+
+ obj->GetPrivate(context, privateKey).ToLocal(&result);
+
+ return result;
+}
+
+static void SetNativeType(v8::Isolate *isolate, const v8::Local &obj, NativeType type) {
+ v8::Local name = ConvertToV8String(isolate, "__type");
+ v8::Local typeValue = v8::Number::New(isolate, (double) type).As();
+ SetPrivateValue(isolate, obj, name, typeValue);
+}
+
+inline static NativeType GetNativeType(v8::Isolate *isolate, const v8::Local &obj) {
+ if (!obj->IsNullOrUndefined() && obj->IsObject()) {
+ v8::Local name = ConvertToV8String(isolate, "__type");
+ auto ret = GetPrivateValue(isolate, obj.As(), name);
+ auto context = isolate->GetCurrentContext();
+
+ if (!ret.IsEmpty() && ret->IsNumber()) {
+ auto value = (int) ret->NumberValue(context).ToChecked();
+ if (value >= (int) NativeType::CanvasGradient &&
+ value <= (int) NativeType::WebGLSync) {
+ return (NativeType) value;
+ }
+ }
+ }
+
+ return NativeType::None;
+}
+
+
+//template
+//inline static rust::Slice
+//GetArrayBufferData(v8::Local &array) {
+// auto buf = array->GetBackingStore()->Data();
+// auto size = array->ByteLength();
+//
+// rust::Slice slice(reinterpret_cast(buf), size);
+// return std::move(slice);
+//}
+
+
+//template
+//inline static rust::Slice
+//GetTypedArrayData(v8::Local &array) {
+// auto buf = array->Buffer();
+// auto offset = array->ByteOffset();
+// auto size = buf->ByteLength();
+// rust::Slice slice(reinterpret_cast(buf->GetBackingStore()->Data()) + offset,
+// (size / sizeof(T)));
+// return std::move(slice);
+//}
+
+
+
+static void SetFastMethod(v8::Isolate* isolate,
+ v8::Local that,
+ const char* name,
+ v8::FunctionCallback slow_callback,
+ const v8::CFunction* c_function,
+ v8::Local data) {
+ v8::Local t =
+ v8::FunctionTemplate::New(isolate,
+ slow_callback,
+ data,
+ v8::Local(),
+ 0,
+ v8::ConstructorBehavior::kThrow,
+ v8::SideEffectType::kHasSideEffect,
+ c_function);
+ // kInternalized strings are created in the old space.
+ const v8::NewStringType type = v8::NewStringType::kInternalized;
+ v8::Local name_string =
+ v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
+ that->Set(name_string, t);
+}
+static void SetFastMethod(v8::Local context,
+ v8::Local that,
+ const char* name,
+ v8::FunctionCallback slow_callback,
+ const v8::CFunction* c_function,
+ v8::Local data = v8::Local()) {
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::Local function =
+ v8::FunctionTemplate::New(isolate,
+ slow_callback,
+ data,
+ v8::Local(),
+ 0,
+ v8::ConstructorBehavior::kThrow,
+ v8::SideEffectType::kHasSideEffect,
+ c_function)
+ ->GetFunction(context)
+ .ToLocalChecked();
+ const v8::NewStringType type = v8::NewStringType::kInternalized;
+ v8::Local name_string =
+ v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
+ that->Set(context, name_string, function).Check();
+}
+
+static void SetFastMethodNoSideEffect(v8::Local context,
+ v8::Local that,
+ const char* name,
+ v8::FunctionCallback slow_callback,
+ const v8::CFunction* c_function,
+ v8::Local data) {
+ v8::Isolate* isolate = context->GetIsolate();
+ v8::Local function =
+ v8::FunctionTemplate::New(isolate,
+ slow_callback,
+ data,
+ v8::Local(),
+ 0,
+ v8::ConstructorBehavior::kThrow,
+ v8::SideEffectType::kHasNoSideEffect,
+ c_function)
+ ->GetFunction(context)
+ .ToLocalChecked();
+ const v8::NewStringType type = v8::NewStringType::kInternalized;
+ v8::Local name_string =
+ v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
+ that->Set(context, name_string, function).Check();
+}
+static void SetFastMethodNoSideEffect(v8::Isolate* isolate,
+ v8::Local that,
+ const char* name,
+ v8::FunctionCallback slow_callback,
+ const v8::CFunction* c_function,
+ v8::Local data) {
+ v8::Local t =
+ v8::FunctionTemplate::New(isolate,
+ slow_callback,
+ data,
+ v8::Local(),
+ 0,
+ v8::ConstructorBehavior::kThrow,
+ v8::SideEffectType::kHasNoSideEffect,
+ c_function);
+ // kInternalized strings are created in the old space.
+ const v8::NewStringType type = v8::NewStringType::kInternalized;
+ v8::Local name_string =
+ v8::String::NewFromUtf8(isolate, name, type).ToLocalChecked();
+ that->Set(name_string, t);
+}
diff --git a/packages/core/platforms/ios/src/cpp/JSIRuntime.cpp b/packages/core/platforms/ios/src/cpp/JSIRuntime.cpp
new file mode 100644
index 000000000..88df04617
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/JSIRuntime.cpp
@@ -0,0 +1,21 @@
+//
+// Created by Osei Fortune on 14/12/2022.
+//
+
+#include "CoreJSIModule.h"
+#include "JSIRuntime.h"
+
+
+extern "C" void NSMain(const v8::FunctionCallbackInfo &args) {
+ auto isolate = args.GetIsolate();
+ auto len = args.Length();
+
+ if (len != 5) {
+ auto errMsg = v8::String::NewFromUtf8(isolate, "Wrong number of arguments (expected 5)");
+ auto err = v8::Exception::Error(errMsg.ToLocalChecked());
+ isolate->ThrowException(err);
+ return;
+ }
+
+ CoreJSIModule::install(isolate);
+}
diff --git a/packages/core/platforms/ios/src/cpp/JSIRuntime.h b/packages/core/platforms/ios/src/cpp/JSIRuntime.h
new file mode 100644
index 000000000..b08d61f92
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/JSIRuntime.h
@@ -0,0 +1,7 @@
+//
+// Created by Osei Fortune on 14/12/2022.
+//
+
+#include "CoreJSIModule.h"
+
+extern "C" void NSMain(const v8::FunctionCallbackInfo &args);
diff --git a/packages/core/platforms/ios/src/cpp/OneByteStringResource.cpp b/packages/core/platforms/ios/src/cpp/OneByteStringResource.cpp
new file mode 100644
index 000000000..355ae35a5
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/OneByteStringResource.cpp
@@ -0,0 +1,46 @@
+//
+// Created by Osei Fortune on 07/01/2024.
+//
+
+#include "OneByteStringResource.h"
+
+OneByteStringResource::OneByteStringResource(char *string) : string_(string),
+ length_(strlen(string)) {
+
+}
+
+OneByteStringResource::OneByteStringResource(U8Buffer *buffer) : buffer_(buffer) {
+ string_ = (char *) nativescript_core_u8_buffer_get_bytes(buffer);
+ length_ = nativescript_core_u8_buffer_get_length(buffer);
+ usingBuffer_ = true;
+}
+
+OneByteStringResource::OneByteStringResource(CCow *cow) : cow_(cow) {
+ string_ = (char *) nativescript_core_ccow_get_bytes(cow);
+ length_ = nativescript_core_ccow_get_length(cow);
+ usingCow_ = true;
+}
+
+OneByteStringResource::~OneByteStringResource() {
+ if (usingBuffer_) {
+ nativescript_core_u8_buffer_destroy(buffer_);
+ this->string_ = nullptr;
+ this->length_ = 0;
+ }else if(usingCow_){
+ nativescript_core_ccow_destroy(cow_);
+ this->string_ = nullptr;
+ this->length_ = 0;
+ } else {
+ nativescript_core_string_destroy((char *) this->string_);
+ this->string_ = nullptr;
+ this->length_ = 0;
+ }
+}
+
+const char *OneByteStringResource::data() const {
+ return this->string_;
+}
+
+size_t OneByteStringResource::length() const {
+ return this->length_;
+}
diff --git a/packages/core/platforms/ios/src/cpp/OneByteStringResource.h b/packages/core/platforms/ios/src/cpp/OneByteStringResource.h
new file mode 100644
index 000000000..6460597b6
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/OneByteStringResource.h
@@ -0,0 +1,31 @@
+//
+// Created by Osei Fortune on 07/01/2024.
+//
+
+#pragma once
+
+#include "Common.h"
+
+class OneByteStringResource : public v8::String::ExternalOneByteStringResource {
+public:
+ OneByteStringResource(char *string);
+
+ OneByteStringResource(U8Buffer *buffer);
+
+ OneByteStringResource(CCow *cow);
+
+ ~OneByteStringResource();
+
+ const char *data() const override;
+
+ size_t length() const override;
+
+private:
+ const char *string_;
+ size_t length_;
+ U8Buffer *buffer_ = nullptr;
+ CCow *cow_ = nullptr;
+ // todo enum
+ bool usingBuffer_ = false;
+ bool usingCow_ = false;
+};
\ No newline at end of file
diff --git a/packages/core/platforms/ios/src/cpp/TextDecoderImpl.cpp b/packages/core/platforms/ios/src/cpp/TextDecoderImpl.cpp
new file mode 100644
index 000000000..8588bc2e8
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/TextDecoderImpl.cpp
@@ -0,0 +1,187 @@
+//
+// Created by Osei Fortune on 19/04/2022.
+//
+
+#include "TextDecoderImpl.h"
+#include "Caches.h"
+#include "Helpers.h"
+#include "OneByteStringResource.h"
+
+TextDecoderImpl::TextDecoderImpl(TextDecoder* decoder) : decoder_(decoder) {}
+
+void TextDecoderImpl::Init(const v8::Local &canvasModule, v8::Isolate *isolate) {
+ v8::Locker locker(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope(isolate);
+
+ auto ctor = GetCtor(isolate);
+ auto context = isolate->GetCurrentContext();
+ auto func = ctor->GetFunction(context).ToLocalChecked();
+
+ canvasModule->Set(context, ConvertToV8String(isolate, "TextDecoder"), func);
+}
+
+TextDecoderImpl *TextDecoderImpl::GetPointer(v8::Local object) {
+ auto ptr = object->GetInternalField(0).As()->Value();
+ if (ptr == nullptr) {
+ return nullptr;
+ }
+ return static_cast(ptr);
+}
+
+TextDecoder* TextDecoderImpl::GetTextDecoder() {
+ return this->decoder_;
+}
+
+v8::Local TextDecoderImpl::GetCtor(v8::Isolate *isolate) {
+ auto cache = Caches::Get(isolate);
+ auto ctor = cache->TextDecoderTmpl.get();
+ if (ctor != nullptr) {
+ return ctor->Get(isolate);
+ }
+
+ v8::Local ctorTmpl = v8::FunctionTemplate::New(isolate, Ctor);
+ ctorTmpl->InstanceTemplate()->SetInternalFieldCount(1);
+ ctorTmpl->SetClassName(ConvertToV8String(isolate, "TextDecoder"));
+
+ auto tmpl = ctorTmpl->InstanceTemplate();
+ tmpl->SetInternalFieldCount(1);
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "encoding"),
+ Encoding);
+ tmpl->Set(
+ ConvertToV8String(isolate, "decode"),
+ v8::FunctionTemplate::New(isolate, &Decode));
+ cache->TextDecoderTmpl =
+ std::make_unique>(isolate, ctorTmpl);
+ return ctorTmpl;
+}
+
+void TextDecoderImpl::Ctor(const v8::FunctionCallbackInfo &args) {
+ auto count = args.Length();
+ auto value = args[0];
+ auto isolate = args.GetIsolate();
+ if (count == 1 && !value->IsString()) {
+ auto label = value->ToString(isolate->GetCurrentContext()).ToLocalChecked();
+ auto arg = ConvertFromV8String(isolate, label);
+ auto error = "Failed to construct 'TextDecoder': The encoding label provided (" +
+ arg + "') is invalid";
+ isolate->ThrowError(ConvertToV8String(isolate, error));
+ return;
+ }
+
+ std::string encoding("utf-8");
+ if (count == 1) {
+ encoding = ConvertFromV8String(isolate, value);
+ }
+ auto encoder = nativescript_core_text_decoder_create(encoding.c_str());
+
+ auto ret = args.This();
+
+ auto decoder = new TextDecoderImpl(encoder);
+
+ auto ext = v8::External::New(isolate, decoder);
+
+ ret->SetInternalField(0, ext);
+
+ args.GetReturnValue().Set(ret);
+
+}
+
+void
+TextDecoderImpl::Encoding(v8::Local name,
+ const v8::PropertyCallbackInfo &info) {
+ auto ptr = GetPointer(info.This());
+ if (ptr != nullptr) {
+ auto isolate = info.GetIsolate();
+ auto encoding = nativescript_core_text_decoder_get_encoding(ptr->GetTextDecoder());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, encoding));
+ nativescript_core_string_destroy((char*)encoding);
+ return;
+ }
+ info.GetReturnValue().SetEmptyString();
+}
+
+void TextDecoderImpl::Decode(const v8::FunctionCallbackInfo &args) {
+ TextDecoderImpl *ptr = GetPointer(args.This());
+ if (ptr == nullptr) {
+ args.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = args.GetIsolate();
+
+ if (args.Length() == 1) {
+ auto value = args[0];
+ if (value->IsNull() ||
+ value->IsUndefined() ||
+ !value->IsObject()) {
+
+ args.GetIsolate()->ThrowError(
+ "Failed to execute 'decode' on 'TextDecoder': The provided value is not of type '(ArrayBuffer or ArrayBufferView)'"
+ );
+ return;
+ }
+
+ auto buf = value.As();
+
+ if (buf->IsArrayBuffer()) {
+
+ auto buffer = buf.As();
+
+ auto data = static_cast(buffer->GetBackingStore()->Data());
+ auto size = buffer->ByteLength();
+ auto decoded = nativescript_core_text_decoder_decode(
+ ptr->GetTextDecoder(),
+ data, size);
+ //args.GetReturnValue().Set(ConvertToV8String(isolate, decoded.c_str()));
+ auto returnValue = new OneByteStringResource((char *)decoded);
+ auto ret = v8::String::NewExternalOneByte(isolate, returnValue);
+ args.GetReturnValue().Set(ret.ToLocalChecked());
+
+ return;
+ }
+
+
+ if (buf->IsArrayBufferView()) {
+
+ auto buffer = buf.As();
+
+
+ auto store = buffer->Buffer()->GetBackingStore();
+ auto buffer_data = static_cast(store->Data()) + buffer->ByteOffset();
+
+ auto len = buffer->ByteLength();
+
+// v8::Local size;
+//
+// buf->Get(context, ConvertToV8String(isolate, "BYTES_PER_ELEMENT")).ToLocal(&size);
+//
+// size_t len = 0;
+//
+// if(!size.IsEmpty()){
+// len = buffer->Length() * (size_t)size->NumberValue(context).FromMaybe(0);
+// }
+
+ // auto len = buffer->ByteLength();
+
+ auto decoded = nativescript_core_text_decoder_decode_as_cow(
+ ptr->GetTextDecoder(),
+ buffer_data, len);
+
+
+ // args.GetReturnValue().Set(ConvertToV8String(isolate, decoded.c_str()));
+ auto returnValue = new OneByteStringResource(decoded);
+ auto ret = v8::String::NewExternalOneByte(isolate, returnValue);
+ args.GetReturnValue().Set(ret.ToLocalChecked());
+ return;
+ }
+
+
+ args.GetIsolate()->ThrowError(
+ "Failed to execute 'decode' on 'TextDecoder': The provided value is not of type '(ArrayBuffer or ArrayBufferView)'");
+
+
+ }
+
+ args.GetReturnValue().SetEmptyString();
+}
diff --git a/packages/core/platforms/ios/src/cpp/TextDecoderImpl.h b/packages/core/platforms/ios/src/cpp/TextDecoderImpl.h
new file mode 100644
index 000000000..a39288283
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/TextDecoderImpl.h
@@ -0,0 +1,34 @@
+//
+// Created by Osei Fortune on 19/04/2022.
+//
+
+#pragma once
+#include
+#include "Common.h"
+
+class TextDecoderImpl {
+public:
+ TextDecoderImpl(TextDecoder* decoder);
+
+ ~TextDecoderImpl(){
+ nativescript_core_text_decoder_destroy(this->GetTextDecoder());
+ this->decoder_ = nullptr;
+ }
+
+ TextDecoder* GetTextDecoder();
+
+ static void Init(const v8::Local& canvasModule, v8::Isolate *isolate);
+
+ static TextDecoderImpl *GetPointer(v8::Local object);
+
+ static v8::Local GetCtor(v8::Isolate *isolate);
+
+ static void Ctor(const v8::FunctionCallbackInfo &args);
+
+ static void Decode(const v8::FunctionCallbackInfo &args);
+
+ static void Encoding(v8::Local name, const v8::PropertyCallbackInfo &info);
+
+private:
+ TextDecoder* decoder_;
+};
diff --git a/packages/core/platforms/ios/src/cpp/TextEncoderImpl.cpp b/packages/core/platforms/ios/src/cpp/TextEncoderImpl.cpp
new file mode 100644
index 000000000..584e49915
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/TextEncoderImpl.cpp
@@ -0,0 +1,139 @@
+//
+// Created by Osei Fortune on 19/04/2022.
+//
+
+#include "TextEncoderImpl.h"
+#include "Caches.h"
+#include "Helpers.h"
+#include "Common.h"
+
+TextEncoderImpl::TextEncoderImpl(TextEncoder* encoder) : encoder_(encoder) {}
+
+void TextEncoderImpl::Init(const v8::Local& canvasModule, v8::Isolate *isolate) {
+ v8::Locker locker(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope(isolate);
+
+ auto ctor = GetCtor(isolate);
+ auto context = isolate->GetCurrentContext();
+ auto func = ctor->GetFunction(context).ToLocalChecked();
+
+ canvasModule->Set(context, ConvertToV8String(isolate, "TextEncoder"), func);
+}
+
+
+TextEncoderImpl *TextEncoderImpl::GetPointer(v8::Local object) {
+ auto ptr = object->GetInternalField(0).As()->Value();
+ if (ptr == nullptr) {
+ return nullptr;
+ }
+ return static_cast(ptr);
+}
+
+
+v8::Local TextEncoderImpl::GetCtor(v8::Isolate *isolate) {
+ auto cache = Caches::Get(isolate);
+ auto ctor = cache->TextEncoderTmpl.get();
+ if (ctor != nullptr) {
+ return ctor->Get(isolate);
+ }
+
+ v8::Local ctorTmpl = v8::FunctionTemplate::New(isolate, Ctor);
+ ctorTmpl->InstanceTemplate()->SetInternalFieldCount(1);
+ ctorTmpl->SetClassName(ConvertToV8String(isolate, "TextEncoder"));
+
+ auto tmpl = ctorTmpl->InstanceTemplate();
+ tmpl->SetInternalFieldCount(1);
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "encoding"),
+ Encoding);
+ tmpl->Set(
+ ConvertToV8String(isolate, "encode"),
+ v8::FunctionTemplate::New(isolate, &Encode));
+ cache->TextEncoderTmpl =
+ std::make_unique>(isolate, ctorTmpl);
+ return ctorTmpl;
+}
+
+
+void TextEncoderImpl::Ctor(const v8::FunctionCallbackInfo &args) {
+ auto count = args.Length();
+ auto value = args[0];
+ auto isolate = args.GetIsolate();
+ if (count == 1 && !value->IsString()) {
+ auto label = value->ToString(isolate->GetCurrentContext()).ToLocalChecked();
+ auto arg = ConvertFromV8String(isolate, label);
+ auto error = "Failed to construct 'TextEncoder': The encoding label provided (" +
+ arg + "') is invalid";
+ isolate->ThrowError(ConvertToV8String(isolate, error));
+ return;
+ }
+
+ std::string encoding("utf-8");
+ if (count == 1) {
+ encoding = ConvertFromV8String(isolate, value);
+ }
+ auto encoder =nativescript_core_text_encoder_create(encoding.c_str());
+
+ auto ret = args.This();
+
+ auto txtEncoder = new TextEncoderImpl(encoder);
+
+ auto ext = v8::External::New(isolate, txtEncoder);
+
+ ret->SetInternalField(0, ext);
+
+ args.GetReturnValue().Set(ret);
+
+}
+
+
+void
+TextEncoderImpl::Encoding(v8::Local name,
+ const v8::PropertyCallbackInfo &info) {
+ auto ptr = GetPointer(info.This());
+ if (ptr != nullptr) {
+ auto isolate = info.GetIsolate();
+ auto encoding = nativescript_core_text_encoder_get_encoding(ptr->GetTextEncoder());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, encoding));
+ nativescript_core_string_destroy((char*)encoding);
+ return;
+ }
+ info.GetReturnValue().SetEmptyString();
+}
+
+void TextEncoderImpl::Encode(const v8::FunctionCallbackInfo &args) {
+ TextEncoderImpl *ptr = GetPointer(args.This());
+ if (ptr == nullptr) {
+ args.GetReturnValue().SetUndefined();
+ return;
+ }
+ auto isolate = args.GetIsolate();
+
+ auto text = args[0];
+
+ auto encoded =nativescript_core_text_encoder_encode(ptr->GetTextEncoder(), ConvertFromV8String(isolate, text).c_str());
+
+ auto data =nativescript_core_u8_buffer_get_bytes_mut(encoded);
+
+ auto length =nativescript_core_u8_buffer_get_length(encoded);
+
+ auto store = v8::ArrayBuffer::NewBackingStore(data, length,
+ [](void *data, size_t length,
+ void *deleter_data) {
+ if (deleter_data != nullptr) {
+ nativescript_core_u8_buffer_destroy((U8Buffer *)deleter_data);
+ }
+ },
+ encoded);
+
+ auto buf = v8::ArrayBuffer::New(isolate, std::move(store));
+
+ auto ret = v8::Uint8ClampedArray::New(buf, 0, length);
+
+ args.GetReturnValue().Set(ret);
+}
+
+TextEncoder* TextEncoderImpl::GetTextEncoder() {
+ return this->encoder_;
+}
diff --git a/packages/core/platforms/ios/src/cpp/TextEncoderImpl.h b/packages/core/platforms/ios/src/cpp/TextEncoderImpl.h
new file mode 100644
index 000000000..3144eda08
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/TextEncoderImpl.h
@@ -0,0 +1,37 @@
+//
+// Created by Osei Fortune on 19/04/2022.
+//
+
+#pragma once
+
+#include
+#include "Common.h"
+
+
+class TextEncoderImpl {
+
+public:
+ TextEncoderImpl(TextEncoder* encoder);
+ ~TextEncoderImpl() {
+ nativescript_core_text_encoder_destroy(this->GetTextEncoder());
+ this->encoder_ = nullptr;
+ }
+
+ TextEncoder* GetTextEncoder();
+
+ static void Init(const v8::Local& canvasModule, v8::Isolate *isolate);
+
+ static TextEncoderImpl *GetPointer(v8::Local object);
+
+ static v8::Local GetCtor(v8::Isolate *isolate);
+
+ static void Ctor(const v8::FunctionCallbackInfo &args);
+
+ static void Encode(const v8::FunctionCallbackInfo &args);
+
+ static void
+ Encoding(v8::Local name, const v8::PropertyCallbackInfo &info);
+
+private:
+ TextEncoder* encoder_;
+};
diff --git a/packages/core/platforms/ios/src/cpp/URLImpl.cpp b/packages/core/platforms/ios/src/cpp/URLImpl.cpp
new file mode 100644
index 000000000..6351fb059
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/URLImpl.cpp
@@ -0,0 +1,465 @@
+//
+// Created by Osei Fortune on 07/01/2024.
+//
+
+#include "URLImpl.h"
+#include "Caches.h"
+#include "Helpers.h"
+#include "OneByteStringResource.h"
+
+URLImpl::URLImpl(URL *url) : url_(url) {}
+
+void URLImpl::Init(const v8::Local &canvasModule, v8::Isolate *isolate) {
+ v8::Locker locker(isolate);
+ v8::Isolate::Scope isolate_scope(isolate);
+ v8::HandleScope handle_scope(isolate);
+
+ auto ctor = GetCtor(isolate);
+ auto context = isolate->GetCurrentContext();
+ auto func = ctor->GetFunction(context).ToLocalChecked();
+
+ canvasModule->Set(context, ConvertToV8String(isolate, "URL"), func);
+}
+
+URLImpl *URLImpl::GetPointer(v8::Local object) {
+ auto ptr = object->GetInternalField(0).As()->Value();
+ if (ptr == nullptr) {
+ return nullptr;
+ }
+ return static_cast(ptr);
+}
+
+URL *URLImpl::GetURL() {
+ return this->url_;
+}
+
+v8::Local URLImpl::GetCtor(v8::Isolate *isolate) {
+ auto cache = Caches::Get(isolate);
+ auto ctor = cache->URLTmpl.get();
+ if (ctor != nullptr) {
+ return ctor->Get(isolate);
+ }
+
+ v8::Local ctorTmpl = v8::FunctionTemplate::New(isolate, Ctor);
+ ctorTmpl->InstanceTemplate()->SetInternalFieldCount(1);
+ ctorTmpl->SetClassName(ConvertToV8String(isolate, "URL"));
+
+ auto tmpl = ctorTmpl->InstanceTemplate();
+ tmpl->SetInternalFieldCount(1);
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "hash"),
+ GetHash, SetHash);
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "host"),
+ GetHost, SetHost);
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "hostname"),
+ GetHostName, SetHostName);
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "href"),
+ GetHref, SetHref);
+
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "origin"),
+ GetOrigin);
+
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "password"),
+ GetPassword, SetPassword);
+
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "pathname"),
+ GetPathName, SetPathName);
+
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "port"),
+ GetPort, SetPort);
+
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "protocol"),
+ GetProtocol, SetProtocol);
+
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "search"),
+ GetSearch, SetSearch);
+
+ tmpl->SetAccessor(
+ ConvertToV8String(isolate, "username"),
+ GetUserName, SetUserName);
+
+ tmpl->Set(ConvertToV8String(isolate, "toString"),
+ v8::FunctionTemplate::New(isolate, &ToString));
+
+
+ ctorTmpl->Set(ConvertToV8String(isolate, "canParse"),
+ v8::FunctionTemplate::New(isolate, &CanParse));
+
+ cache->URLTmpl =
+ std::make_unique>(isolate, ctorTmpl);
+ return ctorTmpl;
+}
+
+void URLImpl::Ctor(const v8::FunctionCallbackInfo &args) {
+ auto count = args.Length();
+ auto value = args[0];
+ auto isolate = args.GetIsolate();
+ if (count >= 1 && !value->IsString()) {
+ isolate->ThrowException(v8::Exception::TypeError(ConvertToV8String(isolate, "")));
+ return;
+ }
+
+
+ URL *url;
+
+ if (count > 1) {
+ url = nativescript_core_url_create(ConvertFromV8String(isolate, args[0]).c_str(),
+ ConvertFromV8String(isolate, args[1]).c_str());
+ } else {
+ url = nativescript_core_url_create(ConvertFromV8String(isolate, args[0]).c_str(), nullptr);
+ }
+
+ auto ret = args.This();
+
+ auto decoder = new URLImpl(url);
+
+ auto ext = v8::External::New(isolate, decoder);
+
+ ret->SetInternalField(0, ext);
+
+ args.GetReturnValue().Set(ret);
+
+}
+
+
+void URLImpl::GetHash(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_hash(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetHash(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_hash(ptr->GetURL(), val.c_str());
+}
+
+
+void URLImpl::GetHost(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_host(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetHost(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_host(ptr->GetURL(), val.c_str());
+}
+
+
+void URLImpl::GetHostName(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_host_name(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetHostName(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_host_name(ptr->GetURL(), val.c_str());
+}
+
+
+void URLImpl::GetHref(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_href(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetHref(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_href(ptr->GetURL(), val.c_str());
+}
+
+void URLImpl::GetOrigin(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_origin(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::GetPassword(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_password(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetPassword(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_password(ptr->GetURL(), val.c_str());
+}
+
+void URLImpl::GetPathName(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_pathname(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetPathName(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_pathname(ptr->GetURL(), val.c_str());
+}
+
+void URLImpl::GetPort(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_port(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetPort(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_port(ptr->GetURL(), val.c_str());
+}
+
+void URLImpl::GetProtocol(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_protocol(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetProtocol(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_protocol(ptr->GetURL(), val.c_str());
+}
+
+
+void URLImpl::GetSearch(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_search(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetSearch(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_search(ptr->GetURL(), val.c_str());
+}
+
+
+void URLImpl::GetUserName(v8::Local property,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ info.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = info.GetIsolate();
+
+ auto value = nativescript_core_url_username(ptr->GetURL());
+ info.GetReturnValue().Set(ConvertToV8String(isolate, value));
+ nativescript_core_string_destroy((char *) value);
+
+}
+
+void URLImpl::SetUserName(v8::Local property,
+ v8::Local value,
+ const v8::PropertyCallbackInfo &info) {
+ URLImpl *ptr = GetPointer(info.This());
+ if (ptr == nullptr) {
+ return;
+ }
+ auto isolate = info.GetIsolate();
+ auto context = isolate->GetCurrentContext();
+ auto val = ConvertFromV8String(isolate, value->ToString(context).ToLocalChecked());
+ nativescript_core_url_set_username(ptr->GetURL(), val.c_str());
+}
+
+
+void URLImpl::ToString(const v8::FunctionCallbackInfo &args) {
+ URLImpl *ptr = GetPointer(args.This());
+ if (ptr == nullptr) {
+ args.GetReturnValue().SetEmptyString();
+ return;
+ }
+ auto isolate = args.GetIsolate();
+
+ auto value = nativescript_core_url_to_string(ptr->GetURL());
+
+ auto returnValue = new OneByteStringResource(value);
+ auto ret = v8::String::NewExternalOneByte(isolate, returnValue);
+ args.GetReturnValue().Set(ret.ToLocalChecked());
+}
+
+
+void URLImpl::CanParse(const v8::FunctionCallbackInfo &args) {
+ auto isolate = args.GetIsolate();
+ bool value;
+ auto count = args.Length();
+
+ if (count > 1) {
+ value = nativescript_core_url_can_parse(ConvertFromV8String(isolate, args[0]).c_str(),
+ ConvertFromV8String(isolate, args[1]).c_str());
+ } else {
+ value = nativescript_core_url_can_parse(ConvertFromV8String(isolate, args[0]).c_str(),
+ nullptr);
+ }
+
+ args.GetReturnValue().Set(value);
+}
diff --git a/packages/core/platforms/ios/src/cpp/URLImpl.h b/packages/core/platforms/ios/src/cpp/URLImpl.h
new file mode 100644
index 000000000..28817e722
--- /dev/null
+++ b/packages/core/platforms/ios/src/cpp/URLImpl.h
@@ -0,0 +1,119 @@
+//
+// Created by Osei Fortune on 07/01/2024.
+//
+
+#pragma once
+
+#include
+#include "Common.h"
+
+class URLImpl {
+public:
+ URLImpl(URL *url);
+
+ ~URLImpl() {
+ nativescript_core_url_destroy(this->GetURL());
+ this->url_ = nullptr;
+ }
+
+ URL *GetURL();
+
+ static void Init(const v8::Local &canvasModule, v8::Isolate *isolate);
+
+ static URLImpl *GetPointer(v8::Local