diff --git a/.gitignore b/.gitignore
index 211d1fa57..feae384ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,13 @@ node_modules
target/
vendor/
-pax-chassis-macos/pax-dev-harness-macos/build
+.swiftpm
+.build
+
+
+xcuserdata
+
+pax-chassis-macos/interface/build
pax-example/build
pax-example/.pax/
pax-create-sandbox/
@@ -16,5 +22,5 @@ Cargo.lock
## VScode project configuration files
.vscode/
-pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/project.xcworkspace/xcuserdata/**/*
-pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/xcuserdata/**/*
+pax-chassis-macos/interface/interface.xcodeproj/project.xcworkspace/xcuserdata/**/*
+pax-chassis-macos/interface/interface.xcodeproj/xcuserdata/**/*
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index b8454501e..c3c11088e 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -3,6 +3,8 @@
+
+
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 6922e2702..8e4602afb 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,7 +17,7 @@ exclude = [
"pax-compiler/new-project-template",
"pax-example",
"pax-properties-coproduct",
- "pax-chassis-macos/pax-dev-harness-macos",
+ "pax-chassis-macos/interface",
"pax-create-sandbox",
"pax-language-server",
]
diff --git a/README.md b/README.md
index 9447469d0..a41308ee4 100644
--- a/README.md
+++ b/README.md
@@ -16,33 +16,70 @@ Writing Pax is intended to feel familiar and the language borrows many ideas fro
Following is a simple Pax component called `IncrementMe`:
```rust
-//File: increment-me.rs
-
+//File: lib.rs
use pax_lang::*;
-use pax_std::{Text};
-use pax_std::forms::{Button, ArgsButtonSubmit};
-use pax_std::layout::{Stacker};
+use pax_lang::api::*;
+use pax_std::primitives::*;
+use pax_std::types::*;
+use pax_std::types::text::*;
+use pax_std::components::Stacker;
/// Defines the Pax component `IncrementMe`, with template & settings specified in `increment-me.pax`.
#[derive(Pax)]
-#[file("increment-me.pax")]
+#[main]
+#[file("increment-me.pax")]
pub struct IncrementMe {
- pub num_clicks: Property
+ pub num_clicks: Property,
+ pub message: Property,
}
+
impl IncrementMe {
- pub async fn increment(&self, args: ArgsButtonSubmit) {
- let old_num_clicks = self.num_clicks.get();
- self.num_clicks.set(old_num_clicks + 1);
- }
-}
+ pub fn handle_did_mount(&mut self, ctx: RuntimeContext) {
+ self.num_clicks.set(0);
+ self.message.set("0 clicks".to_string());
+ }
+ pub fn increment(&mut self, ctx: RuntimeContext, args: ArgsClick){
+ let old_num_clicks = self.num_clicks.get();
+ self.num_clicks.set(old_num_clicks + 1);
+ self.message.set(format!("{} clicks", self.num_clicks.get()));
+ }
+
+}
```
```rust
-//File: increment-me.pax
+//increment-me.pax
+
+
+
+@handlers{
+ did_mount:handle_did_mount
+}
-
-
-
-
+@settings {
+ .centered {
+ x: 50%
+ y: 50%
+ anchor_x: 50%
+ anchor_y: 50%
+ }
+ .small {
+ width: 120px
+ height: 120px
+ }
+ #text {
+ style: {
+ font: {Font::system("Times New Roman", FontStyle::Normal, FontWeight::Bold)},
+ font_size: 32px,
+ fill: {Color::rgba(1.0, 1.0, 1.0, 1.0)},
+ align_vertical: TextAlignVertical::Center,
+ align_horizontal: TextAlignHorizontal::Center,
+ align_multiline: TextAlignHorizontal::Center
+ }
+ }
+}
```
Any Pax component like the example above may be included inside other Pax components, or may be mounted as the root of a stand-alone app.
@@ -107,24 +144,38 @@ Read more in [The Pax Docs](https://docs.pax.dev/)
### To build Pax projects as native macOS apps
- Building macOS apps requires running a Mac with macOS. This is a constraint enforced technically and legally by Apple.
-- Install xcode `>=14.3` and Xcode command line utils: `xcode-select --install`
-- SDK Version `macosx13.3`, Xcode version `>=14.3`
+- Install xcode `>=15.0` and Xcode command line utils: `xcode-select --install`
+- Make sure to accept Xcode's license agreement (prompted during Xcode startup for the first time)
+- SDK Version `macosx13.3`, Xcode version `>=15.0`
- Current Minimum Deployment `13.0`
+- Install all necessary build architectures for Rust, so that binaries can be built for both Intel and Apple Silicon macs
+ ```
+ rustup target add aarch64-apple-darwin x86_64-apple-darwin
+ ```
+
+### To build Pax projects as native iOS apps
+
+- Follow instructions for building native macOS apps, above
+- Install all necessary build architectures for Rust, so that binaries can be built for iOS and simulator targets:
+ ```
+ rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
+ ```
+- Install [ios simulator through Xcode](https://developer.apple.com/documentation/safari-developer-tools/adding-additional-simulators)
#### Support matrix:
| | Web browsers | Native iOS | Native Android | Native macOS | Native Windows | Native Linux |
|-----------------------------------------|---------------|---------------------|-------------------|---------------------|-----------------------------|--------------|
-| Development harness & chassis | ✅ | ⏲ | ⏲ | ✅ | ⏲ | ⏲ |
-| 2D rendering and UIs | ✅
Canvas | ⏲
CoreGraphics | ⏲
Cairo | ✅
CoreGraphics | ⏲
Direct2D | ⏲
Cairo |
+| Development harness & chassis | ✅ | ✅ | ⏲ | ✅ | ⏲ | ⏲ |
+| 2D rendering and UIs | ✅
Canvas | ✅
CoreGraphics | ⏲
Cairo | ✅
CoreGraphics | ⏲
Direct2D | ⏲
Cairo |
| 3D rendering and UIs | ⏲ | ⏲ | ⏲ | ⏲ | ⏲ | ⏲ |
-| Vector graphics APIs | ✅ | ⏲ | ⏲ | ✅ | ⏲ | ⏲ |
-| 2D layouts | ✅ | ⏲ | ⏲ | ✅ | ⏲ | ⏲ |
-| Animation APIs | ✅ | ⏲ | ⏲ | ✅ | ⏲ | ⏲ |
-| Native text rendering | ✅
DOM | ⏲
UIKit | ⏲
android:\* | ✅
SwiftUI | ⏲
System.Windows.Forms | ⏲
GTK |
-| Native form elements | ⏲
DOM | ⏲
UIKit | ⏲
android:\* | ⏲
SwiftUI | ⏲
System.Windows.Forms | ⏲
GTK |
-| Native event handling (e.g. Click, Tap) | ✅ | ⏲ | ⏲ | ✅ | ⏲ | ⏲ |
-| Rust host language | ✅
WASM | ⏲
LLVM | ⏲
LLVM | ✅
LLVM | ⏲
LLVM | ⏲
LLVM |
+| Vector graphics APIs | ✅ | ✅ | ⏲ | ✅ | ⏲ | ⏲ |
+| 2D layouts | ✅ | ✅ | ⏲ | ✅ | ⏲ | ⏲ |
+| Animation APIs | ✅ | ✅ | ⏲ | ✅ | ⏲ | ⏲ |
+| Native text rendering | ✅
DOM | ✅
SwiftUI | ⏲
android:\* | ✅
SwiftUI | ⏲
System.Windows.Forms | ⏲
GTK |
+| Native form elements | ⏲
DOM | ⏲
SwiftUI | ⏲
android:\* | ⏲
SwiftUI | ⏲
System.Windows.Forms | ⏲
GTK |
+| Native event handling (e.g. Click, Tap) | ✅ | ✅ | ⏲ | ✅ | ⏲ | ⏲ |
+| Rust host language | ✅
WASM | ✅
LLVM | ⏲
LLVM | ✅
LLVM | ⏲
LLVM | ⏲
LLVM |
| JS/TypeScript host language | ⏲ | ⏲ | ⏲ | ⏲ | ⏲ | ⏲ |
| Legend: |
diff --git a/lab-journal-zb.md b/lab-journal-zb.md
index e9e612104..b3a7f9d7f 100644
--- a/lab-journal-zb.md
+++ b/lab-journal-zb.md
@@ -2780,9 +2780,9 @@ focused on enabling multi-arch builds, partly to chase down the errors coming
from xcodebuild:
```
-Ld /Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/InstallationBuildProductsLocation/Applications/Pax\ macOS.app/Contents/MacOS/Pax\ macOS normal (in target 'Pax macOS' from project 'pax-dev-harness-macos')
- cd /Users/zack/code/pax/pax-example/.pax/chassis/MacOS/pax-dev-harness-macos
- /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -target x86_64-apple-macos12.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk -L/Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/EagerLinkingTBDs -L/Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/BuildProductsPath/Debug -L/Users/zack/code/pax/pax-example/.pax/chassis/MacOS/pax-dev-harness-macos/../target/debug -F/Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/EagerLinkingTBDs -F/Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/BuildProductsPath/Debug -filelist /Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/pax-dev-harness-macos.build/Debug/Pax\ macOS.build/Objects-normal/x86_64/Pax\ macOS.LinkFileList -Xlinker -rpath -Xlinker @executable_path/../Frameworks -Xlinker -object_path_lto -Xlinker /Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/pax-dev-harness-macos.build/Debug/Pax\ macOS.build/Objects-normal/x86_64/Pax\ macOS_lto.o -Xlinker -export_dynamic -Xlinker -no_deduplicate -Xlinker -final_output -Xlinker /Applications/Pax\ macOS.app/Contents/MacOS/Pax\ macOS -fobjc-link-runtime -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -L/usr/lib/swift -Xlinker -add_ast_path -Xlinker /Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/pax-dev-harness-macos.build/Debug/Pax\ macOS.build/Objects-normal/x86_64/Pax_macOS.swiftmodule -lpaxchassismacos -lpaxchassismacos -Xlinker -dependency_info -Xlinker /Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/pax-dev-harness-macos.build/Debug/Pax\ macOS.build/Objects-normal/x86_64/Pax\ macOS_dependency_info.dat -o /Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/InstallationBuildProductsLocation/Applications/Pax\ macOS.app/Contents/MacOS/Pax\ macOS
+Ld /Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/InstallationBuildProductsLocation/Applications/Pax\ macOS.app/Contents/MacOS/Pax\ macOS normal (in target 'Pax macOS' from project 'interface')
+ cd /Users/zack/code/pax/pax-example/.pax/chassis/MacOS/interface
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -target x86_64-apple-macos12.0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.1.sdk -L/Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/EagerLinkingTBDs -L/Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/BuildProductsPath/Debug -L/Users/zack/code/pax/pax-example/.pax/chassis/MacOS/interface/../target/debug -F/Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/EagerLinkingTBDs -F/Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/BuildProductsPath/Debug -filelist /Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/interface.build/Debug/Pax\ macOS.build/Objects-normal/x86_64/Pax\ macOS.LinkFileList -Xlinker -rpath -Xlinker @executable_path/../Frameworks -Xlinker -object_path_lto -Xlinker /Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/interface.build/Debug/Pax\ macOS.build/Objects-normal/x86_64/Pax\ macOS_lto.o -Xlinker -export_dynamic -Xlinker -no_deduplicate -Xlinker -final_output -Xlinker /Applications/Pax\ macOS.app/Contents/MacOS/Pax\ macOS -fobjc-link-runtime -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -L/usr/lib/swift -Xlinker -add_ast_path -Xlinker /Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/interface.build/Debug/Pax\ macOS.build/Objects-normal/x86_64/Pax_macOS.swiftmodule -lpaxchassismacos -lpaxchassismacos -Xlinker -dependency_info -Xlinker /Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/IntermediateBuildFilesPath/interface.build/Debug/Pax\ macOS.build/Objects-normal/x86_64/Pax\ macOS_dependency_info.dat -o /Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/InstallationBuildProductsLocation/Applications/Pax\ macOS.app/Contents/MacOS/Pax\ macOS
ld: warning: ignoring file /Users/zack/code/pax/pax-example/.pax/chassis/MacOS/target/debug/libpaxchassismacos.dylib, building for macOS-x86_64 but attempting to link with file built for macOS-arm64
Undefined symbols for architecture x86_64:
"_pax_dealloc_message_queue", referenced from:
@@ -2800,7 +2800,7 @@ clang: error: linker command failed with exit code 1 (use -v to see invocation)
The following build commands failed:
- Ld /Users/zack/Library/Developer/Xcode/DerivedData/pax-dev-harness-macos-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/InstallationBuildProductsLocation/Applications/Pax\ macOS.app/Contents/MacOS/Pax\ macOS normal (in target 'Pax macOS' from project 'pax-dev-harness-macos')
+ Ld /Users/zack/Library/Developer/Xcode/DerivedData/interface-ceupzrmwryakhafqxlfbcvhpgytw/Build/Intermediates.noindex/ArchiveIntermediates/Pax\ macOS/InstallationBuildProductsLocation/Applications/Pax\ macOS.app/Contents/MacOS/Pax\ macOS normal (in target 'Pax macOS' from project 'interface')
(1 failure)
```
@@ -3481,3 +3481,98 @@ Sketch addtl. functionality needed to support "edit this website in playground"
[-] Publish (can start with manual)
[-] Manifest for files
[-] upload relevant files (lib.rs, website_desktop, website_mobile
+
+
+
+### On native iOS builds
+
+We are 90% of the way to supporting iOS, given the shared Swift + CoreGraphics layers with macOS. Speccing out what's needed to achieve alpha iOS support:
+
+[x] Split out shared logic into SPM packages
+ [x] Configure macOS project to consume shared packages; get build working
+[x] For proactive cleanliness, break out the cartridge (dylib) into a SPM package, so that consuming it is streamlined and simple across macOS / iOS
+ [x] Wrap all the way from .dylib -> SwiftUI View; this includes creating a .Framework
+ [x] Consume that exposed View in both macOS & iOS
+[x] Refactor (or redo, as needed) macos project to consume new deps
+[ ] Compiler work
+ [x] Refactor compiler internals to adapt to new cartridge / framework / swift package structure: macOS
+ [x] Configure pax-chassis-macos/interface/pax-app-macos to load the swift packages as relative dirs
+ [x] Get e2e build working in-place with pax-chassis-macos (no codegen); embed a placeholder cartridge + resources (bouncing logo?)
+ [x] After copying everything into .pax, patch (1) resources and (2) the dylib into pax-chassis-common/pax-swift-cartridge, then
+ [x] Build the resulting, patched, codegenned macOS project
+ [x] Handle architectures: aarch64 and x86_64;
+ [x] Bundle targets into xcframework
+ [x] Create default carts for xcframework along the way
+ [x] Multithread the dylib builds
+ [x] Handle release vs. debug
+ [x] Handle updates to assets; bundle into pax-swift-cartridge Resources
+ [X] Extend pax CLI + compiler to support --target=ios, firing up simulator if present on machine
+ [x] Refactor macOS-specific deps, e.g. NS* and CVDisplayLink
+ [x] set up xcframework manually and achieve hello world build of xcodeproject
+ [x] add ios target
+ [x] Handle build architectures: aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
+ [x] automate copying & lipo of dylibs
+ [x] manage xcodebuild shell command + firing up simulator
+ [ ] Handle relative paths + inter-dylib deps
+ [ ] Manually update xcframework structure
+ [ ] use `install_name_tool` to change Rust-generated absolute paths into relative paths
+ [ ] get iOS project building with manual changes
+ [ ]
+[ ] Make better default cartridge for default bundling (e.g. bouncing Pax logo)
+ [ ] Clean xcframework binaries from git history for leaner clones; replace with lighter-weight release builds if straight-forward
+[ ] Fix undefined out-of-canvas pixels on iOS (either lock scrolling into bounds with a simple check, or handle canvas clearing ?)
+
+From Apple developer forums:
+```
+If you want to build a framework that supports iOS and the iOS Simulator, construct an XCFramework with:
+
+One element for iOS containing just the arm64 architecture
+
+Another element for the iOS Simulator containing both arm64 and x86_64 architectures
+```
+
+
+Issue with hard-coded vestigial paths in dylib — our built dylibs include absolute paths pointing to ....../libpaxchassismacos.dylib
+
+
+```
+otool -L PaxCartridge
+PaxCartridge (architecture x86_64):
+ /Users/zack/code/pax/pax-example/.pax/pkg/pax-chassis-macos/target/x86_64-apple-ios/release/deps/libpaxchassismacos.dylib (compatibility version 0.0.0, current version 0.0.0)
+ /System/Library/Frameworks/CoreText.framework/CoreText (compatibility version 1.0.0, current version 1.0.0)
+ /System/Library/Frameworks/CoreGraphics.framework/CoreGraphics (compatibility version 64.0.0, current version 1774.0.1)
+ /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 2048.1.101)
+ /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
+ /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.0.0)
+ /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
+ /System/Library/Frameworks/Security.framework/Security (compatibility version 1.0.0, current version 61040.2.2)
+ /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 2048.1.101)
+PaxCartridge (architecture arm64):
+ /Users/zack/code/pax/pax-example/.pax/pkg/pax-chassis-macos/target/aarch64-apple-ios-sim/release/deps/libpaxchassismacos.dylib (compatibility version 0.0.0, current version 0.0.0)
+ /System/Library/Frameworks/CoreText.framework/CoreText (compatibility version 1.0.0, current version 1.0.0)
+ /System/Library/Frameworks/CoreGraphics.framework/CoreGraphics (compatibility version 64.0.0, current version 1774.0.1)
+ /System/Library/Frameworks/CoreFoundation.framework/CoreFoundation (compatibility version 150.0.0, current version 2048.1.101)
+ /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
+ /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1336.0.0)
+ /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
+ /System/Library/Frameworks/Security.framework/Security (compatibility version 1.0.0, current version 61040.2.2)
+ /System/Library/Frameworks/Foundation.framework/Foundation (compatibility version 300.0.0, current version 2048.1.101)
+```
+
+1. These pax-chassis-macos paths almost certainly come from the "pre-built" PaxCartridges that I made manually to get to iOS hello world.
+ These should be replaced with correctly prebuilt packages, from pax-chassis-ios. They should also use @rpath instead of hard-coded dep paths.
+
+2. current best-bet approach to handle the nested dylib deps: create a nested framework (for each arch target, also consider whether lipo is necessary; probably is)
+ this allows embedding the dep .dylib alongside the entrypoint .dylib. Then in the entrypoint .dylib, use `install_name_tool` or similar to
+ update the path to an @rpath/ relative path, using some trial and error to get to a place that xcode respects the provided path. Something like:
+
+```
+MyLibrary.xcframework
+├── ios-arm64
+│ ├── MyLibrary.framework
+│ ├── Dependency1.framework
+│ └── Dependency2.framework
+└── ...
+```
+
+Get this working entirely manually first, then automate in pax-compiler. (validate by `pax clean` and ensuring that builds still run.)
\ No newline at end of file
diff --git a/pax-chassis-common/Cargo.toml b/pax-chassis-common/Cargo.toml
new file mode 100644
index 000000000..5ec99cafe
--- /dev/null
+++ b/pax-chassis-common/Cargo.toml
@@ -0,0 +1,31 @@
+[package]
+name = "pax-chassis-common"
+version = "0.9.9"
+authors = ["Zack Brown "]
+edition = "2021"
+description = "Shared resources for Pax Chassis"
+license = "MIT OR Apache-2.0"
+homepage = "https://pax.dev/"
+repository = "https://www.github.com/pax-lang/pax"
+include = ["src/**/*","pax-swift-common/**/*"]
+
+[workspace]
+
+[lib]
+
+[dependencies]
+piet = "0.6.0"
+piet-coregraphics = "0.6.0"
+pax-core = { path = "../pax-core", version="0.9.9" }
+pax-cartridge = {path="../pax-cartridge", version="0.9.9"}
+pax-message = {path = "../pax-message", version="0.9.9"}
+pax-runtime-api = {path = "../pax-runtime-api", version="0.9.9"}
+pax-properties-coproduct = {path="../pax-properties-coproduct", version="0.9.9"}
+lazy_static = "1.4.0"
+mut_static = "5.0.0"
+#be cautious about core-graphics' version number --
+#ideally this would be locked with `piet` (the specified version should exactly match the version used
+#internally by piet-coregraphics, e.g. 0.6.0 => 0.22.3)
+core-graphics = "0.22.3"
+serde = "1.0.159"
+flexbuffers = "2.0.0"
diff --git a/pax-chassis-common/pax-swift-cartridge/Package.swift b/pax-chassis-common/pax-swift-cartridge/Package.swift
new file mode 100644
index 000000000..a21d3328b
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/Package.swift
@@ -0,0 +1,32 @@
+// swift-tools-version: 5.9
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "PaxSwiftCartridge",
+ platforms: [
+ .macOS(.v12),
+ .iOS(.v13)
+ ],
+ products: [
+ .library(
+ name: "PaxCartridge",
+ targets: ["PaxCartridge", "PaxCartridgeAssets"]
+ ),
+ .library(
+ name: "PaxCartridgeAssets",
+ targets: ["PaxCartridgeAssets"]
+ ),
+ ],
+ targets: [
+ .binaryTarget(
+ name: "PaxCartridge",
+ path: "PaxCartridge.xcframework"
+ ),
+ .target(
+ name: "PaxCartridgeAssets",
+ resources: [.process("Resources")]
+ )
+ ]
+)
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/Info.plist b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/Info.plist
new file mode 100644
index 000000000..225d58a20
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/Info.plist
@@ -0,0 +1,59 @@
+
+
+
+
+ AvailableLibraries
+
+
+ BinaryPath
+ PaxCartridge.framework/PaxCartridge
+ LibraryIdentifier
+ ios-arm64_x86_64-simulator
+ LibraryPath
+ PaxCartridge.framework
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ ios
+ SupportedPlatformVariant
+ simulator
+
+
+ BinaryPath
+ PaxCartridge.framework/PaxCartridge
+ LibraryIdentifier
+ macos-arm64_x86_64
+ LibraryPath
+ PaxCartridge.framework
+ SupportedArchitectures
+
+ arm64
+ x86_64
+
+ SupportedPlatform
+ macos
+
+
+ BinaryPath
+ PaxCartridge.framework/PaxCartridge
+ LibraryIdentifier
+ ios-arm64
+ LibraryPath
+ PaxCartridge.framework
+ SupportedArchitectures
+
+ arm64
+
+ SupportedPlatform
+ ios
+
+
+ CFBundlePackageType
+ XFWK
+ XCFrameworkFormatVersion
+ 1.0
+
+
diff --git a/pax-chassis-macos/src/paxchassismacos.h b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Headers/PaxCartridge.h
similarity index 67%
rename from pax-chassis-macos/src/paxchassismacos.h
rename to pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Headers/PaxCartridge.h
index 2120e0398..e7b6f013f 100644
--- a/pax-chassis-macos/src/paxchassismacos.h
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Headers/PaxCartridge.h
@@ -1,6 +1,7 @@
-//
+//
// Header to expose Rust data & logic via FFI -- if it isn't here, it doesn't exist to Swift.
-// See also: `pax-chassis-macos/src/lib.rs` where this logic is exposed
+//
+// SEE ALSO: `pax-chassis-macos/src/lib.rs` where this logic is managed.
#include
#include
@@ -8,13 +9,13 @@
#include
typedef struct NativeMessageQueue {
- uint8_t *data_ptr;
- uint64_t length;
+ uint8_t *data_ptr;
+ uint64_t length;
} NativeMessageQueue;
typedef struct InterruptBuffer {
- const void *data_ptr;
- uint64_t length;
+ const void *data_ptr;
+ uint64_t length;
} InterruptBuffer;
typedef struct PaxEngineContainer PaxEngineContainer;
@@ -26,8 +27,8 @@ void pax_dealloc_engine(struct PaxEngineContainer * container);
void pax_interrupt(struct PaxEngineContainer *engine_container, const void * interrupt);
struct NativeMessageQueue *pax_tick(struct PaxEngineContainer *engine_container,
- void *cgContext,
- float width,
- float height);
+ void *cgContext,
+ float width,
+ float height);
void pax_dealloc_message_queue(struct NativeMessageQueue *queue);
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Info.plist b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Info.plist
new file mode 100644
index 000000000..29273b3c2
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Info.plist
@@ -0,0 +1,44 @@
+
+
+
+
+
+ CFBundleName
+ PaxCartridge
+
+
+ CFBundleIdentifier
+ dev.pax.PaxCartridge
+
+
+ CFBundleShortVersionString
+ 1.0.0
+
+ CFBundleVersion
+ 1
+
+
+ CFBundlePackageType
+ FMWK
+
+
+ CFBundleSupportedPlatforms
+
+ iOS
+
+
+
+
+ MinimumOSVersion
+ 15.0
+
+
+ CFBundleExecutable
+ PaxCartridge
+
+
+ CFBundleDevelopmentRegion
+ en
+
+
+
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Modules/module.modulemap b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Modules/module.modulemap
new file mode 100644
index 000000000..1f802a9fe
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module PaxCartridge {
+ umbrella header "../Headers/PaxCartridge.h"
+ export *
+ module * { export * }
+}
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/PaxCartridge b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/PaxCartridge
new file mode 100755
index 000000000..dce7ca695
Binary files /dev/null and b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64/PaxCartridge.framework/PaxCartridge differ
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Headers/PaxCartridge.h b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Headers/PaxCartridge.h
new file mode 100644
index 000000000..e7b6f013f
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Headers/PaxCartridge.h
@@ -0,0 +1,34 @@
+//
+// Header to expose Rust data & logic via FFI -- if it isn't here, it doesn't exist to Swift.
+//
+// SEE ALSO: `pax-chassis-macos/src/lib.rs` where this logic is managed.
+
+#include
+#include
+#include
+#include
+
+typedef struct NativeMessageQueue {
+ uint8_t *data_ptr;
+ uint64_t length;
+} NativeMessageQueue;
+
+typedef struct InterruptBuffer {
+ const void *data_ptr;
+ uint64_t length;
+} InterruptBuffer;
+
+typedef struct PaxEngineContainer PaxEngineContainer;
+
+struct PaxEngineContainer *pax_init(void (*logger)(const char*));
+
+void pax_dealloc_engine(struct PaxEngineContainer * container);
+
+void pax_interrupt(struct PaxEngineContainer *engine_container, const void * interrupt);
+
+struct NativeMessageQueue *pax_tick(struct PaxEngineContainer *engine_container,
+ void *cgContext,
+ float width,
+ float height);
+
+void pax_dealloc_message_queue(struct NativeMessageQueue *queue);
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Info.plist b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Info.plist
new file mode 100644
index 000000000..ef27f3120
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Info.plist
@@ -0,0 +1,44 @@
+
+
+
+
+
+ CFBundleName
+ PaxCartridge
+
+
+ CFBundleIdentifier
+ dev.pax.PaxCartridge
+
+
+ CFBundleShortVersionString
+ 1.0.0
+
+ CFBundleVersion
+ 1
+
+
+ CFBundlePackageType
+ FMWK
+
+
+ CFBundleSupportedPlatforms
+
+ iossimulator
+
+
+
+
+ MinimumOSVersion
+ 15.0
+
+
+ CFBundleExecutable
+ PaxCartridge
+
+
+ CFBundleDevelopmentRegion
+ en
+
+
+
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Modules/module.modulemap b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Modules/module.modulemap
new file mode 100644
index 000000000..1f802a9fe
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module PaxCartridge {
+ umbrella header "../Headers/PaxCartridge.h"
+ export *
+ module * { export * }
+}
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/PaxCartridge b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/PaxCartridge
new file mode 100755
index 000000000..77dad22d8
Binary files /dev/null and b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ios-arm64_x86_64-simulator/PaxCartridge.framework/PaxCartridge differ
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Headers/PaxCartridge.h b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Headers/PaxCartridge.h
new file mode 100644
index 000000000..e7b6f013f
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Headers/PaxCartridge.h
@@ -0,0 +1,34 @@
+//
+// Header to expose Rust data & logic via FFI -- if it isn't here, it doesn't exist to Swift.
+//
+// SEE ALSO: `pax-chassis-macos/src/lib.rs` where this logic is managed.
+
+#include
+#include
+#include
+#include
+
+typedef struct NativeMessageQueue {
+ uint8_t *data_ptr;
+ uint64_t length;
+} NativeMessageQueue;
+
+typedef struct InterruptBuffer {
+ const void *data_ptr;
+ uint64_t length;
+} InterruptBuffer;
+
+typedef struct PaxEngineContainer PaxEngineContainer;
+
+struct PaxEngineContainer *pax_init(void (*logger)(const char*));
+
+void pax_dealloc_engine(struct PaxEngineContainer * container);
+
+void pax_interrupt(struct PaxEngineContainer *engine_container, const void * interrupt);
+
+struct NativeMessageQueue *pax_tick(struct PaxEngineContainer *engine_container,
+ void *cgContext,
+ float width,
+ float height);
+
+void pax_dealloc_message_queue(struct NativeMessageQueue *queue);
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Info.plist b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Info.plist
new file mode 100644
index 000000000..a070a1c6e
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Info.plist
@@ -0,0 +1,44 @@
+
+
+
+
+
+ CFBundleName
+ PaxCartridge
+
+
+ CFBundleIdentifier
+ dev.pax.PaxCartridge
+
+
+ CFBundleShortVersionString
+ 1.0.0
+
+ CFBundleVersion
+ 1
+
+
+ CFBundlePackageType
+ FMWK
+
+
+ CFBundleSupportedPlatforms
+
+ macOS
+
+
+
+
+ MinimumOSVersion
+ 12.0
+
+
+ CFBundleExecutable
+ PaxCartridge
+
+
+ CFBundleDevelopmentRegion
+ en
+
+
+
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Modules/module.modulemap b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Modules/module.modulemap
new file mode 100644
index 000000000..1f802a9fe
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/Modules/module.modulemap
@@ -0,0 +1,5 @@
+framework module PaxCartridge {
+ umbrella header "../Headers/PaxCartridge.h"
+ export *
+ module * { export * }
+}
diff --git a/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/PaxCartridge b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/PaxCartridge
new file mode 100755
index 000000000..d09735f62
Binary files /dev/null and b/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/macos-arm64_x86_64/PaxCartridge.framework/PaxCartridge differ
diff --git a/pax-chassis-common/pax-swift-cartridge/README.md b/pax-chassis-common/pax-swift-cartridge/README.md
new file mode 100644
index 000000000..2f690d7c4
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/README.md
@@ -0,0 +1,11 @@
+# pax-swift-cartridge
+
+Holds the Swift Package Manager package + configuration for a Pax cartridge.
+
+This is used by both macOS and iOS builds.
+
+ 1. Configures dylib dependency (built Pax+Rust cartridge)
+ 2. Exposes a SwiftUI View for consumption by developers or full-app chassis
+
+This directory is used as a codegen template — the final built and dylib-patched version of this Swift package will
+sit inside userland `.pax/pkg/pax-chassis-common/pax-swift-cartridge`
\ No newline at end of file
diff --git a/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Empty.swift b/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Empty.swift
new file mode 100644
index 000000000..3b9ebedc6
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Empty.swift
@@ -0,0 +1 @@
+public class PaxCartridgeBundleLocator {}
\ No newline at end of file
diff --git a/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Resources/assets/images/pax-logo-light.png b/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Resources/assets/images/pax-logo-light.png
new file mode 100644
index 000000000..0aacb3190
Binary files /dev/null and b/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Resources/assets/images/pax-logo-light.png differ
diff --git a/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Resources/assets/images/pax-logo.png b/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Resources/assets/images/pax-logo.png
new file mode 100644
index 000000000..cfbc54f54
Binary files /dev/null and b/pax-chassis-common/pax-swift-cartridge/Sources/PaxCartridgeAssets/Resources/assets/images/pax-logo.png differ
diff --git a/pax-chassis-common/pax-swift-cartridge/copy-dylibs-from-pax-example-build.sh b/pax-chassis-common/pax-swift-cartridge/copy-dylibs-from-pax-example-build.sh
new file mode 100755
index 000000000..51c4e7c73
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/copy-dylibs-from-pax-example-build.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Extracts .frameworks from xcframework, rebuilds xcframework.
+# Used to rely on xcodebuild's sanitary bundling process for the fragile xcframework structure
+
+set -e
+
+cp -r ../../pax-example/.pax/pkg/pax-chassis-common/pax-swift-cartridge/PaxCartridge.xcframework/ ./PaxCartridge.xcframework/
\ No newline at end of file
diff --git a/pax-chassis-common/pax-swift-cartridge/rebuild-xcframework.sh b/pax-chassis-common/pax-swift-cartridge/rebuild-xcframework.sh
new file mode 100755
index 000000000..0c0f70256
--- /dev/null
+++ b/pax-chassis-common/pax-swift-cartridge/rebuild-xcframework.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# Extracts .frameworks from xcframework, rebuilds xcframework.
+# Used to rely on xcodebuild's sanitary bundling process for the fragile xcframework structure
+
+set -e
+
+# An array of architectures
+archs=("ios-arm64" "iossimulator-multiarch" "macos-multiarch")
+
+# Iterate over each architecture and perform the operations
+for arch in "${archs[@]}"; do
+ mkdir -p $arch/PaxCartridge.framework
+ cp -r PaxCartridge.xcframework/$arch/PaxCartridge.framework $arch/
+done
+
+rm -rf PaxCartridge.xcframework/
+
+# Construct the xcodebuild command
+cmd="xcodebuild -create-xcframework"
+
+for arch in "${archs[@]}"; do
+ cmd="$cmd -framework $arch/PaxCartridge.framework"
+done
+
+cmd="$cmd -output PaxCartridge.xcframework"
+
+# Execute the xcodebuild command
+eval $cmd
+
+# Cleanup the temporary directories
+for arch in "${archs[@]}"; do
+ rm -rf $arch/
+done
\ No newline at end of file
diff --git a/pax-chassis-common/pax-swift-common/.gitignore b/pax-chassis-common/pax-swift-common/.gitignore
new file mode 100644
index 000000000..3b2981208
--- /dev/null
+++ b/pax-chassis-common/pax-swift-common/.gitignore
@@ -0,0 +1,9 @@
+.DS_Store
+/.build
+/Packages
+/*.xcodeproj
+xcuserdata/
+DerivedData/
+.swiftpm/config/registries.json
+.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
+.netrc
diff --git a/pax-chassis-common/pax-swift-common/Package.swift b/pax-chassis-common/pax-swift-common/Package.swift
new file mode 100644
index 000000000..beb09b6bc
--- /dev/null
+++ b/pax-chassis-common/pax-swift-common/Package.swift
@@ -0,0 +1,37 @@
+// swift-tools-version: 5.9
+// The swift-tools-version declares the minimum version of Swift required to build this package.
+
+import PackageDescription
+
+let package = Package(
+ name: "PaxSwiftCommon",
+ platforms: [
+ .macOS(.v12),
+ .iOS(.v15)
+ ],
+ products: [
+ // Products define the executables and libraries a package produces, making them visible to other packages.
+ .library(
+ name: "Messages",
+ targets: ["Messages"]),
+ .library(
+ name: "Rendering",
+ targets: ["Rendering"]),
+ .library(
+ name: "FlexBuffers",
+ targets: ["FlexBuffers"]),
+ ],
+ targets: [
+ // Targets are the basic building blocks of a package, defining a module or a test suite.
+ // Targets can depend on other targets in this package and products from dependencies.
+
+ .target(
+ name: "FlexBuffers"),
+ .target(
+ name: "Rendering",
+ dependencies: ["Messages"]),
+ .target(
+ name: "Messages",
+ dependencies: ["FlexBuffers"]),
+ ]
+)
diff --git a/pax-chassis-common/pax-swift-common/README.md b/pax-chassis-common/pax-swift-common/README.md
new file mode 100644
index 000000000..6061f3d8d
--- /dev/null
+++ b/pax-chassis-common/pax-swift-common/README.md
@@ -0,0 +1,4 @@
+# pax-swift-common
+
+Common swift logic, packaged as an SPM package, shared by both iOS and macOS (e.g. FlexBuffers and Message structs)
+
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/FlexBuffers/FlexBufferBuilder.swift b/pax-chassis-common/pax-swift-common/Sources/FlexBuffers/FlexBufferBuilder.swift
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/FlexBuffers/FlexBufferBuilder.swift
rename to pax-chassis-common/pax-swift-common/Sources/FlexBuffers/FlexBufferBuilder.swift
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/FlexBuffers/FlexBuffers.h b/pax-chassis-common/pax-swift-common/Sources/FlexBuffers/FlexBuffers.h
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/FlexBuffers/FlexBuffers.h
rename to pax-chassis-common/pax-swift-common/Sources/FlexBuffers/FlexBuffers.h
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/FlexBuffers/FlexBuffers.swift b/pax-chassis-common/pax-swift-common/Sources/FlexBuffers/FlexBuffers.swift
similarity index 98%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/FlexBuffers/FlexBuffers.swift
rename to pax-chassis-common/pax-swift-common/Sources/FlexBuffers/FlexBuffers.swift
index af34a9856..6d8aaef06 100644
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/FlexBuffers/FlexBuffers.swift
+++ b/pax-chassis-common/pax-swift-common/Sources/FlexBuffers/FlexBuffers.swift
@@ -11,6 +11,26 @@ import CoreGraphics
// MARK: FlexBuffers Builder logic
+
+protocol WritableValueType {}
+
+extension Int: WritableValueType {}
+extension Int8: WritableValueType {}
+extension Int16: WritableValueType {}
+extension Int32: WritableValueType {}
+extension Int64: WritableValueType {}
+
+extension UInt: WritableValueType {}
+extension UInt8: WritableValueType {}
+extension UInt16: WritableValueType {}
+extension UInt32: WritableValueType {}
+extension UInt64: WritableValueType {}
+
+extension Float32: WritableValueType {}
+extension Float64: WritableValueType {}
+
+extension Bool: WritableValueType {}
+
public class FlexBuffer {
let initialSize : Int
@@ -250,7 +270,8 @@ public class FlexBuffer {
write(value: length, size: byteWidth)
sloc = offset
for c in buffer {
- write(value: c, size: 1)
+ let ci = UInt8(c)
+ write(value: ci, size: 1)
}
write(value: UInt8(0), size: 1)
return bitWidth
@@ -414,8 +435,10 @@ public class FlexBuffer {
offset += paddingSize(bufSize: offset, scalarSize: UInt8(byteWidth))
return UInt8(byteWidth)
}
+
+
- fileprivate func write(value : T, size : UInt8) {
+ fileprivate func write(value : T, size : UInt8) {
var v = value
let newOffest = offset + Int(size)
let prevSize = currentSize
@@ -1099,7 +1122,8 @@ public extension FlexBuffer {
_ = value.withUnsafeBytes { (byte) -> Bool in
for i in 0...allocate(capacity: tokenPointerCurrent)
tokenNamePointerCapacity = tokenPointerCurrent
}
- tokenNamePointerStart.moveAssign(from: tokenPointerStart, count: tokenPointerCurrent)
+ tokenNamePointerStart.moveUpdate(from: tokenPointerStart, count: tokenPointerCurrent)
tokenNamePointerCurrent = tokenPointerCurrent
tokenPointerCurrent = 0
keyIsPresent = true
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Messages.swift b/pax-chassis-common/pax-swift-common/Sources/Messages/Messages.swift
similarity index 79%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Messages.swift
rename to pax-chassis-common/pax-swift-common/Sources/Messages/Messages.swift
index 2c9e9cac6..7b29b1428 100644
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Messages.swift
+++ b/pax-chassis-common/pax-swift-common/Sources/Messages/Messages.swift
@@ -1,21 +1,22 @@
//
// Messages.swift
-// pax-dev-harness-macos
+// interface
//
// Created by Zachary Brown on 5/7/22.
//
import Foundation
import SwiftUI
+import FlexBuffers
/// Agnostic of the type of element, this patch contains only an `id_chain` field, suitable for looking up a NativeElement (e.g. for deletion)
-class AnyCreatePatch {
- var id_chain: [UInt64]
+public class AnyCreatePatch {
+ public var id_chain: [UInt64]
/// Used for clipping -- each `[UInt64]` is an `id_chain` for an associated clipping mask (`Frame`)
- var clipping_ids: [[UInt64]]
+ public var clipping_ids: [[UInt64]]
- init(fb:FlxbReference) {
+ public init(fb:FlxbReference) {
self.id_chain = fb["id_chain"]!.asVector!.makeIterator().map({ fb in
fb.asUInt64!
})
@@ -29,10 +30,10 @@ class AnyCreatePatch {
}
-class AnyDeletePatch {
- var id_chain: [UInt64]
+public class AnyDeletePatch {
+ public var id_chain: [UInt64]
- init(fb:FlxbReference) {
+ public init(fb:FlxbReference) {
self.id_chain = fb.asVector!.makeIterator().map({ fb in
fb.asUInt64!
})
@@ -40,15 +41,15 @@ class AnyDeletePatch {
}
}
-class TextStyle {
- var font: PaxFont
- var fill: Color
- var alignmentMultiline: TextAlignment
- var alignment: Alignment
- var font_size: CGFloat
- var underline: Bool
+public class TextStyle {
+ public var font: PaxFont
+ public var fill: Color
+ public var alignmentMultiline: TextAlignment
+ public var alignment: Alignment
+ public var font_size: CGFloat
+ public var underline: Bool
- init(font: PaxFont, fill: Color, alignmentMultiline: TextAlignment, alignment: Alignment, font_size: CGFloat, underline: Bool) {
+ public init(font: PaxFont, fill: Color, alignmentMultiline: TextAlignment, alignment: Alignment, font_size: CGFloat, underline: Bool) {
self.font = font
self.fill = fill
self.alignmentMultiline = alignmentMultiline
@@ -57,7 +58,7 @@ class TextStyle {
self.underline = underline
}
- func applyPatch(from patch: TextStyleMessage) {
+ public func applyPatch(from patch: TextStyleMessage) {
self.font.applyPatch(fb: patch.font)
@@ -84,18 +85,18 @@ class TextStyle {
}
}
-class TextElement {
- var id_chain: [UInt64]
- var clipping_ids: [[UInt64]]
- var content: String
- var transform: [Float]
- var size_x: Float
- var size_y: Float
- var textStyle: TextStyle
- var depth: UInt?
- var style_link: TextStyle?
+public class TextElement {
+ public var id_chain: [UInt64]
+ public var clipping_ids: [[UInt64]]
+ public var content: String
+ public var transform: [Float]
+ public var size_x: Float
+ public var size_y: Float
+ public var textStyle: TextStyle
+ public var depth: UInt?
+ public var style_link: TextStyle?
- init(id_chain: [UInt64], clipping_ids: [[UInt64]], content: String, transform: [Float], size_x: Float, size_y: Float, textStyle: TextStyle, depth: UInt?, style_link: TextStyle?) {
+ public init(id_chain: [UInt64], clipping_ids: [[UInt64]], content: String, transform: [Float], size_x: Float, size_y: Float, textStyle: TextStyle, depth: UInt?, style_link: TextStyle?) {
self.id_chain = id_chain
self.clipping_ids = clipping_ids
self.content = content
@@ -107,12 +108,12 @@ class TextElement {
self.style_link = style_link
}
- static func makeDefault(id_chain: [UInt64], clipping_ids: [[UInt64]]) -> TextElement {
+ public static func makeDefault(id_chain: [UInt64], clipping_ids: [[UInt64]]) -> TextElement {
let defaultTextStyle = TextStyle(font: PaxFont.makeDefault(), fill: Color(.black), alignmentMultiline: .leading, alignment: .topLeading, font_size: 5.0, underline: false)
return TextElement(id_chain: id_chain, clipping_ids: clipping_ids, content: "", transform: [1,0,0,1,0,0], size_x: 0.0, size_y: 0.0, textStyle: defaultTextStyle, depth: nil, style_link: nil)
}
- func applyPatch(patch: TextUpdatePatch) {
+ public func applyPatch(patch: TextUpdatePatch) {
//no-op to ID, as it is primary key
if let content = patch.content {
@@ -143,13 +144,13 @@ class TextElement {
}
}
-enum TextAlignHorizontal {
+public enum TextAlignHorizontal {
case center
case left
case right
}
-extension TextAlignHorizontal {
+public extension TextAlignHorizontal {
func toTextAlignment() -> TextAlignment {
switch self {
case .center:
@@ -162,14 +163,14 @@ extension TextAlignHorizontal {
}
}
-enum TextAlignVertical {
+public enum TextAlignVertical {
case top
case center
case bottom
}
-func toAlignment(horizontalAlignment: TextAlignHorizontal, verticalAlignment: TextAlignVertical) -> Alignment {
+public func toAlignment(horizontalAlignment: TextAlignHorizontal, verticalAlignment: TextAlignVertical) -> Alignment {
let horizontal: HorizontalAlignment
let vertical: VerticalAlignment
@@ -195,11 +196,11 @@ func toAlignment(horizontalAlignment: TextAlignHorizontal, verticalAlignment: Te
/// A patch representing an image load request from a given id_chain
-class ImageLoadPatch {
- var id_chain: [UInt64]
- var path: String?
+public class ImageLoadPatch {
+ public var id_chain: [UInt64]
+ public var path: String?
- init(fb:FlxbReference) {
+ public init(fb:FlxbReference) {
self.id_chain = fb["id_chain"]!.asVector!.makeIterator().map({ fb in
fb.asUInt64!
})
@@ -208,16 +209,16 @@ class ImageLoadPatch {
}
-class TextStyleMessage {
- var font: FlxbReference
- var fill: Color?
- var font_size: CGFloat?
- var underline: Bool?
- var align_multiline: TextAlignHorizontal?
- var align_horizontal: TextAlignHorizontal?
- var align_vertical: TextAlignVertical?
+public class TextStyleMessage {
+ public var font: FlxbReference
+ public var fill: Color?
+ public var font_size: CGFloat?
+ public var underline: Bool?
+ public var align_multiline: TextAlignHorizontal?
+ public var align_horizontal: TextAlignHorizontal?
+ public var align_vertical: TextAlignVertical?
- init(_ buffer: FlxbReference) {
+ public init(_ buffer: FlxbReference) {
self.font = buffer["font"]!
self.font_size = buffer["font_size"]?.asFloat.map { CGFloat($0) }
@@ -269,17 +270,17 @@ class TextStyleMessage {
}
-class TextUpdatePatch {
- var id_chain: [UInt64]
- var content: String?
- var transform: [Float]?
- var size_x: Float?
- var size_y: Float?
- var depth: UInt?
- var style: TextStyleMessage?
- var style_link: TextStyleMessage?
+public class TextUpdatePatch {
+ public var id_chain: [UInt64]
+ public var content: String?
+ public var transform: [Float]?
+ public var size_x: Float?
+ public var size_y: Float?
+ public var depth: UInt?
+ public var style: TextStyleMessage?
+ public var style_link: TextStyleMessage?
- init(fb: FlxbReference) {
+ public init(fb: FlxbReference) {
self.id_chain = fb["id_chain"]!.asVector!.makeIterator().map({ fb in
fb.asUInt64!
})
@@ -302,20 +303,20 @@ class TextUpdatePatch {
}
///// A patch containing optional fields, representing an update action for the NativeElement of the given id_chain
-//class TextUpdatePatch {
-// var id_chain: [UInt64]
-// var content: String?
-// var transform: [Float]?
-// var size_x: Float?
-// var size_y: Float?
-// var fontBuffer: FlxbReference
-// var fill: Color?
-// var align_multiline: TextAlignHorizontal?
-// var align_vertical: TextAlignVertical?
-// var align_horizontal: TextAlignHorizontal?
+//public class TextUpdatePatch {
+// public var id_chain: [UInt64]
+// public var content: String?
+// public var transform: [Float]?
+// public var size_x: Float?
+// public var size_y: Float?
+// public var fontBuffer: FlxbReference
+// public var fill: Color?
+// public var align_multiline: TextAlignHorizontal?
+// public var align_vertical: TextAlignVertical?
+// public var align_horizontal: TextAlignHorizontal?
// // New properties
-// var size: CGFloat?
-// var style_link: LinkStyle?
+// public var size: CGFloat?
+// public var style_link: LinkStyle?
//
// init(fb: FlxbReference) {
// self.id_chain = fb["id_chain"]!.asVector!.makeIterator().map({ fb in
@@ -382,7 +383,7 @@ class TextUpdatePatch {
//}
-func extractColorFromBuffer(_ fillBuffer: FlxbReference) -> Color {
+public func extractColorFromBuffer(_ fillBuffer: FlxbReference) -> Color {
if let rgba = fillBuffer["Rgba"], !rgba.isNull {
let stub = fillBuffer["Rgba"]!
return Color(
@@ -404,18 +405,18 @@ func extractColorFromBuffer(_ fillBuffer: FlxbReference) -> Color {
}
}
-enum TextAlignHorizontalMessage: String {
+public enum TextAlignHorizontalMessage: String {
case Left, Center, Right
}
-enum FontStyle: String {
+public enum FontStyle: String {
case normal = "Normal"
case italic = "Italic"
case oblique = "Oblique"
}
extension FontWeight {
- func fontWeight() -> Font.Weight {
+ public func fontWeight() -> Font.Weight {
switch self {
case .thin: return .thin
case .extraLight: return .ultraLight
@@ -430,7 +431,7 @@ extension FontWeight {
}
}
-enum FontWeight: String {
+public enum FontWeight: String {
case thin = "Thin"
case extraLight = "ExtraLight"
case light = "Light"
@@ -442,48 +443,48 @@ enum FontWeight: String {
case black = "Black"
}
-class PaxFont {
- enum PaxFontType {
+public class PaxFont {
+ public enum PaxFontType {
case system(SystemFont)
case web(WebFont)
case local(LocalFont)
}
- struct SystemFont {
+ public struct SystemFont {
let family: String
let style: FontStyle
let weight: FontWeight
}
- struct WebFont {
+ public struct WebFont {
let family: String
let url: URL
let style: FontStyle
let weight: FontWeight
}
- struct LocalFont {
+ public struct LocalFont {
let family: String
let path: URL
let style: FontStyle
let weight: FontWeight
}
- var type: PaxFontType
- var cachedFont: Font?
- var currentSize: CGFloat
+ public var type: PaxFontType
+ public var cachedFont: Font?
+ public var currentSize: CGFloat
- init(type: PaxFontType) {
+ public init(type: PaxFontType) {
self.type = type
self.currentSize = 12
}
- static func makeDefault() -> PaxFont {
+ public static func makeDefault() -> PaxFont {
let defaultSystemFont = SystemFont(family: "Helvetica", style: .normal, weight: .normal)
return PaxFont(type: .system(defaultSystemFont))
}
- func getFont(size: CGFloat) -> Font {
+ public func getFont(size: CGFloat) -> Font {
if let cachedFont = cachedFont, currentSize == size {
return cachedFont
}
@@ -534,7 +535,7 @@ class PaxFont {
- func applyPatch(fb: FlxbReference) {
+ public func applyPatch(fb: FlxbReference) {
if let systemFontMessage = fb["System"] {
if let family = systemFontMessage["family"]?.asString {
let styleMessage = FontStyle(rawValue: systemFontMessage["style"]?.asString ?? "normal") ?? .normal
@@ -562,7 +563,8 @@ class PaxFont {
}
}
- static func isFontRegistered(fontFamily: String) -> Bool {
+ #if os(macOS)
+ public static func isFontRegistered(fontFamily: String) -> Bool {
let fontFamilies = CTFontManagerCopyAvailableFontFamilyNames() as! [String]
if fontFamilies.contains(fontFamily) {
@@ -583,15 +585,22 @@ class PaxFont {
}
}
}
-
return false
+
+ }
+ #elseif os(iOS) || os(tvOS) || os(watchOS)
+ public static func isFontRegistered(fontFamily: String) -> Bool {
+ let availableFontFamilies = UIFont.familyNames
+
+ return availableFontFamilies.contains(fontFamily)
}
+ #endif
}
//
-//class FontFactory {
-//// var family: String
-//// var variant: String
-//// var size: Float
+//public class FontFactory {
+//// public var family: String
+//// public var public variant: String
+//// public var size: Float
//
// func applyPatch(fb: FlxbReference) -> Font {
// print("MAKING FONT")
@@ -640,24 +649,24 @@ class PaxFont {
-class FrameElement {
- var id_chain: [UInt64]
- var transform: [Float]
- var size_x: Float
- var size_y: Float
+public class FrameElement {
+ public var id_chain: [UInt64]
+ public var transform: [Float]
+ public var size_x: Float
+ public var size_y: Float
- init(id_chain: [UInt64], transform: [Float], size_x: Float, size_y: Float) {
+ public init(id_chain: [UInt64], transform: [Float], size_x: Float, size_y: Float) {
self.id_chain = id_chain
self.transform = transform
self.size_x = size_x
self.size_y = size_y
}
- static func makeDefault(id_chain: [UInt64]) -> FrameElement {
+ public static func makeDefault(id_chain: [UInt64]) -> FrameElement {
FrameElement(id_chain: id_chain, transform: [1,0,0,1,0,0], size_x: 0.0, size_y: 0.0)
}
- func applyPatch(patch: FrameUpdatePatch) {
+ public func applyPatch(patch: FrameUpdatePatch) {
//no-op to ID, as it is primary key
if patch.transform != nil {
@@ -675,13 +684,13 @@ class FrameElement {
/// A patch containing optional fields, representing an update action for the NativeElement of the given id_chain
-class FrameUpdatePatch {
- var id_chain: [UInt64]
- var transform: [Float]?
- var size_x: Float?
- var size_y: Float?
+public class FrameUpdatePatch {
+ public var id_chain: [UInt64]
+ public var transform: [Float]?
+ public var size_x: Float?
+ public var size_y: Float?
- init(fb: FlxbReference) {
+ public init(fb: FlxbReference) {
self.id_chain = fb["id_chain"]!.asVector!.makeIterator().map({ fb in
fb.asUInt64!
})
diff --git a/pax-chassis-common/pax-swift-common/Sources/Rendering/Rendering.swift b/pax-chassis-common/pax-swift-common/Sources/Rendering/Rendering.swift
new file mode 100644
index 000000000..d4436e687
--- /dev/null
+++ b/pax-chassis-common/pax-swift-common/Sources/Rendering/Rendering.swift
@@ -0,0 +1,118 @@
+import SwiftUI
+import Messages
+
+public struct NativeRenderingLayer: View {
+
+ public init() {}
+
+ @ObservedObject var textElements : TextElements = TextElements.singleton
+ @ObservedObject var frameElements : FrameElements = FrameElements.singleton
+
+ public func getClippingMask(clippingIds: [[UInt64]]) -> some View {
+
+ var elements : [FrameElement] = []
+
+ clippingIds.makeIterator().forEach( { id_chain in
+ elements.insert(self.frameElements.elements[id_chain]!, at: 0)
+ })
+
+ return ZStack { ForEach(elements, id: \.id_chain) { frameElement in
+ Rectangle()
+ .frame(width: CGFloat(frameElement.size_x), height: CGFloat(frameElement.size_y))
+ .position(x: CGFloat(frameElement.size_x / 2.0), y: CGFloat(frameElement.size_y / 2.0))
+ .transformEffect(CGAffineTransform.init(
+ a: CGFloat(frameElement.transform[0]),
+ b: CGFloat(frameElement.transform[1]),
+ c: CGFloat(frameElement.transform[2]),
+ d: CGFloat(frameElement.transform[3]),
+ tx: CGFloat(frameElement.transform[4]),
+ ty: CGFloat(frameElement.transform[5]))
+ )
+ } }
+ }
+
+ @ViewBuilder
+ public func getPositionedTextGroup(textElement: TextElement) -> some View {
+ let transform = CGAffineTransform.init(
+ a: CGFloat(textElement.transform[0]),
+ b: CGFloat(textElement.transform[1]),
+ c: CGFloat(textElement.transform[2]),
+ d: CGFloat(textElement.transform[3]),
+ tx: CGFloat(textElement.transform[4]),
+ ty: CGFloat(textElement.transform[5])
+ )
+ var text: AttributedString {
+ var attributedString: AttributedString = try! AttributedString(markdown: textElement.content, options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace))
+
+ for run in attributedString.runs {
+ if run.link != nil {
+ if let linkStyle = textElement.style_link {
+ attributedString[run.range].font = linkStyle.font.getFont(size: linkStyle.font_size)
+ if(linkStyle.underline){
+ attributedString[run.range].underlineStyle = .single
+ } else {
+ attributedString[run.range].underlineStyle = .none
+ }
+ attributedString[run.range].foregroundColor = linkStyle.fill
+ }
+ }
+ }
+ return attributedString
+
+ }
+ let textView : some View =
+ Text(text)
+ .foregroundColor(textElement.textStyle.fill)
+ .font(textElement.textStyle.font.getFont(size: textElement.textStyle.font_size))
+ .frame(width: CGFloat(textElement.size_x), height: CGFloat(textElement.size_y), alignment: textElement.textStyle.alignment)
+ .position(x: CGFloat(textElement.size_x / 2.0), y: CGFloat(textElement.size_y / 2.0))
+ .transformEffect(transform)
+ .textSelection(.enabled)
+
+//
+// if !textElement.clipping_ids.isEmpty {
+// textView.mask(getClippingMask(clippingIds: textElement.clipping_ids))
+// } else {
+// textView
+// }
+
+ textView
+ }
+
+ public var body: some View {
+ ZStack{
+ ForEach(Array(self.textElements.elements.values), id: \.id_chain) { textElement in
+ getPositionedTextGroup(textElement: textElement)
+ }
+ }
+ }
+}
+
+public class TextElements: ObservableObject {
+ public static let singleton : TextElements = TextElements()
+
+ @Published public var elements : [[UInt64]: TextElement] = [:]
+
+ public func add(element: TextElement) {
+ self.elements[element.id_chain] = element
+ }
+ public func remove(id: [UInt64]) {
+ self.elements.removeValue(forKey: id)
+ }
+}
+
+public class FrameElements: ObservableObject {
+ public static let singleton : FrameElements = FrameElements()
+
+ @Published public var elements : [[UInt64]: FrameElement] = [:]
+
+ public func add(element: FrameElement) {
+ self.elements[element.id_chain] = element
+ }
+ public func remove(id: [UInt64]) {
+ self.elements.removeValue(forKey: id)
+ }
+ public func get(id: [UInt64]) -> FrameElement? {
+ return self.elements[id]
+ }
+}
diff --git a/pax-chassis-common/pax-swift-common/Tests/PaxSwiftCommonTests/PaxSwiftCommonTests.swift b/pax-chassis-common/pax-swift-common/Tests/PaxSwiftCommonTests/PaxSwiftCommonTests.swift
new file mode 100644
index 000000000..811910067
--- /dev/null
+++ b/pax-chassis-common/pax-swift-common/Tests/PaxSwiftCommonTests/PaxSwiftCommonTests.swift
@@ -0,0 +1,12 @@
+import XCTest
+@testable import PaxSwiftCommon
+
+final class PaxSwiftCommonTests: XCTestCase {
+ func testExample() throws {
+ // XCTest Documenation
+ // https://developer.apple.com/documentation/xctest
+
+ // Defining Test Cases and Test Methods
+ // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods
+ }
+}
diff --git a/pax-chassis-common/src/core_graphics_c_bridge.rs b/pax-chassis-common/src/core_graphics_c_bridge.rs
new file mode 100644
index 000000000..94e0ab20e
--- /dev/null
+++ b/pax-chassis-common/src/core_graphics_c_bridge.rs
@@ -0,0 +1,211 @@
+#![allow(non_snake_case)] //Non-snake-case is used here to help denote foreign structs, e.g. from Swift via C
+
+extern crate core;
+
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::ffi::c_void;
+use std::rc::Rc;
+
+use std::mem::{transmute, ManuallyDrop};
+use std::os::raw::c_char;
+
+use core_graphics::context::CGContext;
+use piet_coregraphics::CoreGraphicsContext;
+
+use flexbuffers;
+use flexbuffers::DeserializationError;
+use serde::Serialize;
+
+use pax_cartridge;
+use pax_core::{InstanceRegistry, PaxEngine};
+
+//Re-export all native message types; used by Swift via FFI.
+//Note that any types exposed by pax_message must ALSO be added to `PaxCartridge.h`
+//in order to be visible to Swift
+pub use pax_message::*;
+use pax_runtime_api::{ArgsClick, ArgsScroll, ModifierKey, MouseButton, MouseEventArgs};
+
+/// Container data structure for PaxEngine, aggregated to support passing across C bridge
+#[repr(C)] //Exposed to Swift via PaxCartridge.h
+pub struct PaxEngineContainer {
+ _engine: *mut PaxEngine>,
+ //NOTE: since that has become a single field, this data structure may be be retired and `*mut PaxEngine` could be passed directly.
+}
+
+/// Allocate an instance of the Pax engine, with a specified root/main component from the loaded `pax_cartridge`.
+#[no_mangle] //Exposed to Swift via PaxCartridge.h
+pub extern "C" fn pax_init(logger: extern "C" fn(*const c_char)) -> *mut PaxEngineContainer {
+ //Initialize a ManuallyDrop-contained PaxEngine, so that a pointer to that
+ //engine can be passed back to Swift via the C (FFI) bridge
+ //This could presumably be cleaned up -- see `pax_dealloc_engine`
+ let instance_registry: Rc>>> =
+ Rc::new(RefCell::new(InstanceRegistry::new()));
+ let main_component_instance =
+ pax_cartridge::instantiate_main_component(Rc::clone(&instance_registry));
+ let expression_table = pax_cartridge::instantiate_expression_table();
+
+ let engine: ManuallyDrop>>> =
+ ManuallyDrop::new(Box::new(PaxEngine::new(
+ main_component_instance,
+ expression_table,
+ pax_runtime_api::PlatformSpecificLogger::MacOS(logger),
+ (1.0, 1.0),
+ instance_registry,
+ )));
+
+ let container = ManuallyDrop::new(Box::new(PaxEngineContainer {
+ _engine: Box::into_raw(ManuallyDrop::into_inner(engine)),
+ }));
+
+ Box::into_raw(ManuallyDrop::into_inner(container))
+}
+
+/// Destroy `engine` and clean up the `ManuallyDrop` container surround it.
+#[no_mangle]
+pub extern "C" fn pax_dealloc_engine(_container: *mut PaxEngineContainer) {
+ //particularly for when we need to support elegant clean-up from attached harness
+ unimplemented!();
+}
+
+/// Send `interrupt`s from the chassis, for example: user input
+/// Note that in any single-threaded environment, these interrupts will happen
+/// synchronously between engine ticks, allowing for safe unwrapping / borrowing
+/// of engine and runtime here.
+#[no_mangle]
+pub extern "C" fn pax_interrupt(
+ engine_container: *mut PaxEngineContainer,
+ buffer: *const InterruptBuffer,
+) {
+ let mut engine = unsafe { Box::from_raw((*engine_container)._engine) };
+ // let slice = unsafe { buffer.as_ref().unwrap() };
+
+ let length: u64 = unsafe {
+ (*buffer).length.try_into().unwrap() // length negative or overflowed
+ };
+
+ let slice = unsafe {
+ if (*buffer).data_ptr.is_null() {
+ &mut []
+ } else {
+ std::slice::from_raw_parts((*buffer).data_ptr, length.try_into().unwrap())
+ }
+ };
+
+ let interrupt_wrapped: Result =
+ flexbuffers::from_slice(slice);
+ let interrupt = interrupt_wrapped.unwrap();
+ match interrupt {
+ NativeInterrupt::Click(args) => {
+ let prospective_hit = engine.get_topmost_element_beneath_ray((args.x, args.y));
+ match prospective_hit {
+ Some(topmost_node) => {
+ let modifiers = args
+ .modifiers
+ .iter()
+ .map(|x| ModifierKey::from(x))
+ .collect();
+ let args_click = ArgsClick {
+ mouse: MouseEventArgs {
+ x: args.x,
+ y: args.y,
+ button: MouseButton::from(args.button),
+ modifiers,
+ },
+ };
+ topmost_node.dispatch_click(args_click);
+ }
+ _ => {}
+ };
+ },
+ NativeInterrupt::Scroll(args) => {
+ let prospective_hit = engine.get_focused_element();
+ match prospective_hit {
+ Some(topmost_node) => {
+ let args_scroll = ArgsScroll {
+ delta_x: args.delta_x,
+ delta_y: args.delta_y,
+ };
+ topmost_node.dispatch_scroll(args_scroll);
+ }
+ _ => {}
+ };
+ },
+ NativeInterrupt::Image(args) => match args {
+ ImageLoadInterruptArgs::Reference(ref_args) => {
+ let ptr = ref_args.image_data as *const u8;
+ let slice = unsafe { std::slice::from_raw_parts(ptr, ref_args.image_data_length) };
+ let owned_data: Vec = slice.to_vec();
+ engine.load_image(
+ ref_args.id_chain,
+ owned_data,
+ ref_args.width,
+ ref_args.height,
+ );
+ }
+ ImageLoadInterruptArgs::Data(_) => {}
+ },
+ _ => {}
+ }
+
+ unsafe { (*engine_container)._engine = Box::into_raw(engine) };
+}
+
+/// Perform full tick of engine, including property computation, lifecycle event handling, and rendering side-effects.
+/// Returns a message queue of native rendering actions encoded as a Flexbuffer via FFI to Swift.
+/// The returned message queue requires explicit deallocation: `pax_deallocate_message_queue`
+#[no_mangle] //Exposed to Swift via PaxCartridge.h
+pub extern "C" fn pax_tick(
+ engine_container: *mut PaxEngineContainer,
+ cgContext: *mut c_void,
+ width: f32,
+ height: f32,
+) -> *mut NativeMessageQueue {
+ // note that f32 is essentially `CFloat`, per: https://doc.rust-lang.org/std/os/raw/type.c_float.html
+ let mut engine = unsafe { Box::from_raw((*engine_container)._engine) };
+
+ let will_cast_cgContext = cgContext as *mut CGContext;
+ let ctx = unsafe { &mut *will_cast_cgContext };
+ let render_context = CoreGraphicsContext::new_y_up(ctx, height as f64, None);
+ (*engine).set_viewport_size((width as f64, height as f64));
+
+ let mut render_contexts = HashMap::new();
+ render_contexts.insert(format!("{}", 0), render_context);
+
+ let messages = (*engine).tick(&mut render_contexts);
+
+ let wrapped_queue = MessageQueue { messages };
+ let mut serializer = flexbuffers::FlexbufferSerializer::new();
+
+ //side-effectfully serialize, mutating `serializer`
+ wrapped_queue.serialize(&mut serializer).unwrap();
+
+ let data_buffer = serializer.take_buffer();
+ let length = data_buffer.len();
+
+ let leaked_data: ManuallyDrop> = ManuallyDrop::new(data_buffer.into_boxed_slice());
+
+ let queue_container = unsafe {
+ transmute(Box::new(NativeMessageQueue {
+ data_ptr: Box::into_raw(ManuallyDrop::into_inner(leaked_data)),
+ length: length as u64,
+ }))
+ };
+
+ //`Box::into_raw` is our necessary manual clean-up, acting as a trigger to drop all of the RefCell::borrow_mut's throughout the tick lifecycle
+ unsafe { (*engine_container)._engine = Box::into_raw(engine) };
+
+ queue_container
+}
+
+/// Required manual cleanup callback from Swift after reading a frame's message queue.
+/// If this is not called after `pax_tick` is invoked, we will have a memory leak.
+#[no_mangle] //Exposed to Swift via PaxCartridge.h
+pub extern "C" fn pax_dealloc_message_queue(queue: *mut NativeMessageQueue) {
+ unsafe {
+ let queue_container = Box::from_raw(queue);
+ let data_buffer = Box::from_raw(queue_container.data_ptr);
+ drop(data_buffer);
+ drop(queue_container);
+ }
+}
diff --git a/pax-chassis-common/src/lib.rs b/pax-chassis-common/src/lib.rs
new file mode 100644
index 000000000..46c08d95f
--- /dev/null
+++ b/pax-chassis-common/src/lib.rs
@@ -0,0 +1 @@
+pub mod core_graphics_c_bridge;
\ No newline at end of file
diff --git a/pax-chassis-ios/Cargo.toml b/pax-chassis-ios/Cargo.toml
new file mode 100644
index 000000000..6a0652c01
--- /dev/null
+++ b/pax-chassis-ios/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "pax-chassis-ios"
+edition = "2021"
+version = "0.9.9"
+authors = ["Zack Brown "]
+license = "MIT OR Apache-2.0"
+homepage = "https://pax.dev/"
+repository = "https://www.github.com/pax-lang/pax"
+description = "Platform-specific chassis allowing Pax cartridges to be executed as native iOS apps"
+
+[lib]
+name = "paxchassisios"
+crate-type = ["cdylib"]
+
+[dependencies]
+pax-chassis-common = {version = "0.9.9", path="../pax-chassis-common"}
+
+# The following empty [workspace] directive is a workaround to satisfy
+# a cargo workspace bug, as documented: https://github.com/rust-lang/cargo/issues/6745
+[workspace]
\ No newline at end of file
diff --git a/pax-chassis-ios/interface/pax-app-ios/pax-app-ios.xcodeproj/project.pbxproj b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..cc4627bcb
--- /dev/null
+++ b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios.xcodeproj/project.pbxproj
@@ -0,0 +1,414 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 60;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1405D1202ACF5B1C006EBEF1 /* PaxViewIos.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1405D11F2ACF5B1C006EBEF1 /* PaxViewIos.swift */; };
+ 1405D1222ACF5B1C006EBEF1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1405D1212ACF5B1C006EBEF1 /* ContentView.swift */; };
+ 1405D1242ACF5B1D006EBEF1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1405D1232ACF5B1D006EBEF1 /* Assets.xcassets */; };
+ 1405D1272ACF5B1D006EBEF1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1405D1262ACF5B1D006EBEF1 /* Preview Assets.xcassets */; };
+ 141DEF6D2AD4E82D000EFF82 /* PaxCartridge in Frameworks */ = {isa = PBXBuildFile; productRef = 141DEF6C2AD4E82D000EFF82 /* PaxCartridge */; };
+ 141DEF6F2AD4E82D000EFF82 /* PaxCartridgeAssets in Frameworks */ = {isa = PBXBuildFile; productRef = 141DEF6E2AD4E82D000EFF82 /* PaxCartridgeAssets */; };
+ 141DEF722AD4E83E000EFF82 /* FlexBuffers in Frameworks */ = {isa = PBXBuildFile; productRef = 141DEF712AD4E83E000EFF82 /* FlexBuffers */; };
+ 141DEF742AD4E83E000EFF82 /* Messages in Frameworks */ = {isa = PBXBuildFile; productRef = 141DEF732AD4E83E000EFF82 /* Messages */; };
+ 141DEF762AD4E83E000EFF82 /* Rendering in Frameworks */ = {isa = PBXBuildFile; productRef = 141DEF752AD4E83E000EFF82 /* Rendering */; };
+ 14BA75902AD4C4DE001B3A61 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14BA758F2AD4C4DE001B3A61 /* Main.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 1405D11C2ACF5B1C006EBEF1 /* Pax iOS (Development).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Pax iOS (Development).app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1405D11F2ACF5B1C006EBEF1 /* PaxViewIos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaxViewIos.swift; sourceTree = ""; };
+ 1405D1212ACF5B1C006EBEF1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
+ 1405D1232ACF5B1D006EBEF1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 1405D1262ACF5B1D006EBEF1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
+ 14BA758F2AD4C4DE001B3A61 /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 1405D1192ACF5B1C006EBEF1 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 141DEF742AD4E83E000EFF82 /* Messages in Frameworks */,
+ 141DEF762AD4E83E000EFF82 /* Rendering in Frameworks */,
+ 141DEF6D2AD4E82D000EFF82 /* PaxCartridge in Frameworks */,
+ 141DEF722AD4E83E000EFF82 /* FlexBuffers in Frameworks */,
+ 141DEF6F2AD4E82D000EFF82 /* PaxCartridgeAssets in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 1405D1132ACF5B1C006EBEF1 = {
+ isa = PBXGroup;
+ children = (
+ 1405D11E2ACF5B1C006EBEF1 /* pax-app-ios */,
+ 1405D11D2ACF5B1C006EBEF1 /* Products */,
+ );
+ sourceTree = "";
+ };
+ 1405D11D2ACF5B1C006EBEF1 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 1405D11C2ACF5B1C006EBEF1 /* Pax iOS (Development).app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 1405D11E2ACF5B1C006EBEF1 /* pax-app-ios */ = {
+ isa = PBXGroup;
+ children = (
+ 1405D11F2ACF5B1C006EBEF1 /* PaxViewIos.swift */,
+ 1405D1212ACF5B1C006EBEF1 /* ContentView.swift */,
+ 1405D1232ACF5B1D006EBEF1 /* Assets.xcassets */,
+ 1405D1252ACF5B1D006EBEF1 /* Preview Content */,
+ 14BA758F2AD4C4DE001B3A61 /* Main.swift */,
+ );
+ path = "pax-app-ios";
+ sourceTree = "";
+ };
+ 1405D1252ACF5B1D006EBEF1 /* Preview Content */ = {
+ isa = PBXGroup;
+ children = (
+ 1405D1262ACF5B1D006EBEF1 /* Preview Assets.xcassets */,
+ );
+ path = "Preview Content";
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 1405D11B2ACF5B1C006EBEF1 /* Pax iOS (Development) */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1405D12A2ACF5B1D006EBEF1 /* Build configuration list for PBXNativeTarget "Pax iOS (Development)" */;
+ buildPhases = (
+ 1405D1182ACF5B1C006EBEF1 /* Sources */,
+ 1405D1192ACF5B1C006EBEF1 /* Frameworks */,
+ 1405D11A2ACF5B1C006EBEF1 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "Pax iOS (Development)";
+ packageProductDependencies = (
+ 141DEF6C2AD4E82D000EFF82 /* PaxCartridge */,
+ 141DEF6E2AD4E82D000EFF82 /* PaxCartridgeAssets */,
+ 141DEF712AD4E83E000EFF82 /* FlexBuffers */,
+ 141DEF732AD4E83E000EFF82 /* Messages */,
+ 141DEF752AD4E83E000EFF82 /* Rendering */,
+ );
+ productName = "pax-app-ios";
+ productReference = 1405D11C2ACF5B1C006EBEF1 /* Pax iOS (Development).app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 1405D1142ACF5B1C006EBEF1 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1500;
+ LastUpgradeCheck = 1500;
+ TargetAttributes = {
+ 1405D11B2ACF5B1C006EBEF1 = {
+ CreatedOnToolsVersion = 15.0;
+ };
+ };
+ };
+ buildConfigurationList = 1405D1172ACF5B1C006EBEF1 /* Build configuration list for PBXProject "pax-app-ios" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 1405D1132ACF5B1C006EBEF1;
+ packageReferences = (
+ 141DEF6B2AD4E82D000EFF82 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */,
+ 141DEF702AD4E83E000EFF82 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-common" */,
+ );
+ productRefGroup = 1405D11D2ACF5B1C006EBEF1 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 1405D11B2ACF5B1C006EBEF1 /* Pax iOS (Development) */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 1405D11A2ACF5B1C006EBEF1 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1405D1272ACF5B1D006EBEF1 /* Preview Assets.xcassets in Resources */,
+ 1405D1242ACF5B1D006EBEF1 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 1405D1182ACF5B1C006EBEF1 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 14BA75902AD4C4DE001B3A61 /* Main.swift in Sources */,
+ 1405D1222ACF5B1C006EBEF1 /* ContentView.swift in Sources */,
+ 1405D1202ACF5B1C006EBEF1 /* PaxViewIos.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1405D1282ACF5B1D006EBEF1 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 1405D1292ACF5B1D006EBEF1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.0;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 1405D12B2ACF5B1D006EBEF1 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"pax-app-ios/Preview Content\"";
+ DEVELOPMENT_TEAM = "";
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchScreen_Generation = YES;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "dev.pax.pax-app-ios";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 1405D12C2ACF5B1D006EBEF1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_IDENTITY = "Don't Code Sign";
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"pax-app-ios/Preview Content\"";
+ DEVELOPMENT_TEAM = "";
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchScreen_Generation = YES;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "dev.pax.pax-app-ios";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1405D1172ACF5B1C006EBEF1 /* Build configuration list for PBXProject "pax-app-ios" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1405D1282ACF5B1D006EBEF1 /* Debug */,
+ 1405D1292ACF5B1D006EBEF1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1405D12A2ACF5B1D006EBEF1 /* Build configuration list for PBXNativeTarget "Pax iOS (Development)" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1405D12B2ACF5B1D006EBEF1 /* Debug */,
+ 1405D12C2ACF5B1D006EBEF1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+
+/* Begin XCLocalSwiftPackageReference section */
+ 141DEF6B2AD4E82D000EFF82 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = "../../../pax-chassis-common/pax-swift-cartridge";
+ };
+ 141DEF702AD4E83E000EFF82 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-common" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = "../../../pax-chassis-common/pax-swift-common";
+ };
+/* End XCLocalSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 141DEF6C2AD4E82D000EFF82 /* PaxCartridge */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = PaxCartridge;
+ };
+ 141DEF6E2AD4E82D000EFF82 /* PaxCartridgeAssets */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = PaxCartridgeAssets;
+ };
+ 141DEF712AD4E83E000EFF82 /* FlexBuffers */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = FlexBuffers;
+ };
+ 141DEF732AD4E83E000EFF82 /* Messages */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = Messages;
+ };
+ 141DEF752AD4E83E000EFF82 /* Rendering */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = Rendering;
+ };
+/* End XCSwiftPackageProductDependency section */
+ };
+ rootObject = 1405D1142ACF5B1C006EBEF1 /* Project object */;
+}
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to pax-chassis-ios/interface/pax-app-ios/pax-app-ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
rename to pax-chassis-ios/interface/pax-app-ios/pax-app-ios.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AccentColor.colorset/Contents.json b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Assets.xcassets/AccentColor.colorset/Contents.json
similarity index 56%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AccentColor.colorset/Contents.json
rename to pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Assets.xcassets/AccentColor.colorset/Contents.json
index 2f0f228e3..eb8789700 100644
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AccentColor.colorset/Contents.json
+++ b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -1,10 +1,6 @@
{
"colors" : [
{
- "color" : {
- "platform" : "universal",
- "reference" : "labelColor"
- },
"idiom" : "universal"
}
],
diff --git a/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Assets.xcassets/AppIcon.appiconset/Contents.json b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 000000000..13613e3ee
--- /dev/null
+++ b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,13 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/Contents.json b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Assets.xcassets/Contents.json
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/Contents.json
rename to pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Assets.xcassets/Contents.json
diff --git a/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/ContentView.swift b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/ContentView.swift
new file mode 100644
index 000000000..151706093
--- /dev/null
+++ b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/ContentView.swift
@@ -0,0 +1,24 @@
+//
+// ContentView.swift
+// pax-app-ios
+//
+// Created by Zack Brown on 10/5/23.
+//
+
+import SwiftUI
+
+struct ContentView: View {
+ var body: some View {
+ VStack {
+ Image(systemName: "globe")
+ .imageScale(.large)
+ .foregroundStyle(.tint)
+ Text("Hello, world!")
+ }
+ .padding()
+ }
+}
+
+#Preview {
+ ContentView()
+}
diff --git a/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Main.swift b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Main.swift
new file mode 100644
index 000000000..3b95a10ee
--- /dev/null
+++ b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Main.swift
@@ -0,0 +1,17 @@
+//
+// Main.swift
+// pax-app-macos
+//
+// Created by Zack Brown on 10/3/23.
+//
+
+import SwiftUI
+
+@main
+struct pax_app_iosApp: App {
+ var body: some Scene {
+ WindowGroup {
+ PaxViewIos().edgesIgnoringSafeArea(.all)
+ }
+ }
+}
diff --git a/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/PaxViewIos.swift b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/PaxViewIos.swift
new file mode 100644
index 000000000..21b0d0753
--- /dev/null
+++ b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/PaxViewIos.swift
@@ -0,0 +1,371 @@
+//
+// ContentView.swift
+// interface
+//
+// Created by Zachary Brown on 4/6/22.
+//
+
+import SwiftUI
+import Foundation
+import FlexBuffers
+import Messages
+import Rendering
+import PaxCartridgeAssets
+import PaxCartridge
+
+struct PaxViewIos: View {
+
+ var canvasView : some View = PaxCanvasViewRepresentable()
+ .frame(minWidth: 300, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
+
+ @State private var previousScrollLocation: CGPoint? = nil
+
+ var body: some View {
+ ZStack {
+ self.canvasView
+ NativeRenderingLayer()
+ }
+ .onAppear {
+ registerFonts()
+ }
+ .gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
+ .onChanged { dragGesture in
+ if let previous = self.previousScrollLocation {
+ let deltaX = dragGesture.location.x - previous.x
+ let deltaY = dragGesture.location.y - previous.y
+
+ let json = String(format: "{\"Scroll\": {\"x\": %f, \"y\": %f, \"delta_x\": %f, \"delta_y\": %f} }",
+ dragGesture.location.x,
+ dragGesture.location.y,
+ -deltaX,
+ -deltaY)
+ sendInterrupt(with: json)
+ }
+
+ self.previousScrollLocation = dragGesture.location
+ }
+ .onEnded { dragGesture in
+ //Reset scroll tracking position
+ self.previousScrollLocation = nil
+
+ // Handle "Click" events — note that we should probably check to ensure that a maximum distance has not been crossed
+ // to rightly handle this as a "click". Currently this is more of a `touchend`.
+ let json = String(format: "{\"Click\": {\"x\": %f, \"y\": %f, \"button\": \"Left\", \"modifiers\":[] } }", dragGesture.location.x, dragGesture.location.y)
+ sendInterrupt(with: json)
+ }
+ )
+ }
+
+ func sendInterrupt(with json: String) {
+ let buffer = try! FlexBufferBuilder.fromJSON(json)
+ buffer.data.withUnsafeBytes { ptr in
+ var ffi_container = InterruptBuffer(data_ptr: ptr.baseAddress!, length: UInt64(ptr.count))
+ withUnsafePointer(to: &ffi_container) { ffi_container_ptr in
+ pax_interrupt(PaxEngineContainer.paxEngineContainer!, ffi_container_ptr)
+ }
+ }
+ }
+
+ func registerFonts() {
+
+ let nestedBundleURL = Bundle.main.url(forResource: "PaxSwiftCartridge_PaxCartridgeAssets", withExtension: "bundle")!
+
+ let resourceBundle = Bundle(url: nestedBundleURL)!
+
+ let resourceURL = resourceBundle.resourceURL!
+
+ let fontFileExtensions = ["ttf", "otf"]
+
+ do {
+ let resourceFiles = try FileManager.default.contentsOfDirectory(at: resourceURL, includingPropertiesForKeys: nil, options: [])
+ for fileURL in resourceFiles {
+ let fileExtension = fileURL.pathExtension.lowercased()
+ if fontFileExtensions.contains(fileExtension) {
+ let fontDescriptors = CTFontManagerCreateFontDescriptorsFromURL(fileURL as CFURL) as! [CTFontDescriptor]
+ if let fontDescriptor = fontDescriptors.first,
+ let postscriptName = CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontNameAttribute) as? String,
+ let fontFamily = CTFontDescriptorCopyAttribute(fontDescriptor, kCTFontFamilyNameAttribute) as? String {
+ if !PaxFont.isFontRegistered(fontFamily: postscriptName) {
+ var errorRef: Unmanaged?
+ if !CTFontManagerRegisterFontsForURL(fileURL as CFURL, .process, &errorRef) {
+ print("Error registering font: \(fontFamily) - PostScript name: \(postscriptName) - \(String(describing: errorRef))")
+ }
+ } else {
+ print("Font already registered: \(fontFamily) - PostScript name: \(postscriptName)")
+ }
+ }
+ }
+ }
+ } catch {
+ print("Error reading font files from resources: \(error)")
+ }
+ }
+
+
+ class PaxEngineContainer {
+ static var paxEngineContainer : OpaquePointer? = nil
+ }
+
+
+
+ struct PaxCanvasViewRepresentable: UIViewRepresentable {
+ typealias UIViewType = PaxCanvasViewIos
+
+ func makeUIView(context: Context) -> PaxCanvasViewIos {
+ let view = PaxCanvasViewIos()
+ return view
+ }
+
+ func updateUIView(_ uiView: PaxCanvasViewIos, context: Context) {
+ }
+ }
+
+
+ class PaxCanvasViewIos: UIView {
+
+ @ObservedObject var textElements = TextElements.singleton
+ @ObservedObject var frameElements = FrameElements.singleton
+ private var displayLink: CADisplayLink?
+
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ createDisplayLink()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ createDisplayLink()
+ }
+
+
+ private var requestAnimationFrameQueue: [() -> Void] = []
+
+ private func processRequestAnimationFrameQueue() {
+ // Execute and remove each closure in the array
+ while !requestAnimationFrameQueue.isEmpty {
+ let closure = requestAnimationFrameQueue.removeFirst()
+ closure()
+ }
+ }
+
+ func requestAnimationFrame(_ closure: @escaping () -> Void) {
+ requestAnimationFrameQueue.append(closure)
+ }
+
+
+ private func createDisplayLink() {
+ displayLink = CADisplayLink(target: self, selector: #selector(handleDisplayLink))
+ displayLink?.add(to: .current, forMode: .common)
+ }
+
+ @objc private func handleDisplayLink() {
+ DispatchQueue.main.async {
+ self.setNeedsDisplay()
+ self.processRequestAnimationFrameQueue()
+ }
+ }
+
+ deinit {
+ displayLink?.invalidate()
+ }
+
+ override func draw(_ rect: CGRect) {
+ super.draw(rect)
+ guard let cgContext = UIGraphicsGetCurrentContext() else { return }
+
+ // Apply affine transform to cgContext to emulate macOS's "y-up" coordinate space.
+ cgContext.translateBy(x: 0, y: rect.height) // Move the origin to the bottom-left
+ cgContext.scaleBy(x: 1.0, y: -1.0) // Reflect over x axis
+
+ if PaxEngineContainer.paxEngineContainer == nil {
+ let swiftLoggerCallback : @convention(c) (UnsafePointer?) -> () = {
+ (msg) -> () in
+ let outputString = String(cString: msg!)
+ print(outputString)
+ }
+
+ PaxEngineContainer.paxEngineContainer = pax_init(swiftLoggerCallback)
+ } else {
+ guard var mutableCGContext = UIGraphicsGetCurrentContext() else { return }
+ let nativeMessageQueue = pax_tick(PaxEngineContainer.paxEngineContainer!, &mutableCGContext, Float(rect.width), Float(rect.height))
+ processNativeMessageQueue(queue: nativeMessageQueue.unsafelyUnwrapped.pointee)
+ pax_dealloc_message_queue(nativeMessageQueue)
+ }
+
+ if currentTickWorkItem != nil {
+ currentTickWorkItem!.cancel()
+ }
+
+ currentTickWorkItem = DispatchWorkItem {
+ self.setNeedsDisplay(rect)
+ self.setNeedsLayout()
+ }
+
+ }
+
+ var currentTickWorkItem : DispatchWorkItem? = nil
+
+ func handleTextCreate(patch: AnyCreatePatch) {
+ textElements.add(element: TextElement.makeDefault(id_chain: patch.id_chain, clipping_ids: patch.clipping_ids))
+ }
+
+ func handleTextUpdate(patch: TextUpdatePatch) {
+ textElements.elements[patch.id_chain]?.applyPatch(patch: patch)
+ textElements.objectWillChange.send()
+ }
+
+ func handleTextDelete(patch: AnyDeletePatch) {
+ self.textElements.remove(id: patch.id_chain)
+ }
+
+ func handleFrameCreate(patch: AnyCreatePatch) {
+ frameElements.add(element: FrameElement.makeDefault(id_chain: patch.id_chain))
+ }
+
+ func handleFrameUpdate(patch: FrameUpdatePatch) {
+ frameElements.elements[patch.id_chain]?.applyPatch(patch: patch)
+ frameElements.objectWillChange.send()
+ }
+
+ func handleFrameDelete(patch: AnyDeletePatch) {
+ frameElements.remove(id: patch.id_chain)
+ }
+
+ func printAllFilesInBundle() {
+ let bundleURL = Bundle.main.bundleURL
+
+ do {
+ let resourceURLs = try FileManager.default.contentsOfDirectory(at: bundleURL, includingPropertiesForKeys: nil, options: [])
+ for url in resourceURLs {
+ print(url.lastPathComponent)
+ }
+ } catch {
+ print("Error: \(error)")
+ }
+ }
+
+ func handleImageLoad(patch: ImageLoadPatch) {
+ Task {
+ do {
+ let fullPatchPath = patch.path!
+ let url = URL(fileURLWithPath: fullPatchPath)
+ let fileNameWithExtension = url.lastPathComponent
+ let fileExtension = url.pathExtension
+ let fileName = String(fileNameWithExtension.prefix(fileNameWithExtension.count - fileExtension.count - 1))
+
+ guard let nestedBundleURL = Bundle.main.url(forResource: "PaxSwiftCartridge_PaxCartridgeAssets", withExtension: "bundle") else {
+ throw NSError(domain: "", code: 99, userInfo: [NSLocalizedDescriptionKey : "PaxCartridgeAssets bundle not found in main bundle. Make sure you have imported PaxCartridgeAssets in Swift."])
+ }
+
+ let assetsBundle = Bundle(url: nestedBundleURL)
+
+ guard let imageURL = assetsBundle?.url(forResource: fileName, withExtension: fileExtension) else {
+ throw NSError(domain: "", code: 100, userInfo: [NSLocalizedDescriptionKey : "Image file not found in nested bundle"])
+ }
+
+ guard let image = UIImage(contentsOfFile: imageURL.path) else {
+ throw NSError(domain: "", code: 101, userInfo: [NSLocalizedDescriptionKey : "Could not create UIImage from data"])
+ }
+
+ guard let cgImage = image.cgImage else {
+ throw NSError(domain: "", code: 102, userInfo: [NSLocalizedDescriptionKey : "Could not retrieve CGImage from UIImage"])
+ }
+
+ let width = cgImage.width
+ let height = cgImage.height
+ let bitsPerComponent = cgImage.bitsPerComponent
+ let bytesPerRow = cgImage.bytesPerRow
+ let totalBytes = height * bytesPerRow
+
+ let colorSpace = CGColorSpaceCreateDeviceRGB()
+ let bitmapInfo = CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue
+
+ guard let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo) else {
+ throw NSError(domain: "", code: 103, userInfo: [NSLocalizedDescriptionKey : "Could not create CGContext"])
+ }
+
+ context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
+
+ guard let data = context.data else {
+ throw NSError(domain: "", code: 104, userInfo: [NSLocalizedDescriptionKey : "Could not retrieve pixel data from context"])
+ }
+
+ let byteBuffer = data.assumingMemoryBound(to: UInt8.self)
+
+ let id_chain : FlxbValueVector = FlxbValueVector.init(values: patch.id_chain.map { (number) -> FlxbValue in
+ return number as FlxbValue
+ })
+ let raw_pointer_uint = UInt(bitPattern: byteBuffer)
+
+ let buffer = try! FlexBufferBuilder.encode(
+ [ "Image": [ "Reference": [
+ "id_chain": id_chain,
+ "image_data": raw_pointer_uint,
+ "image_data_length": totalBytes,
+ "width": width,
+ "height": height,
+ ] as FlxbValueMap] as FlxbValueMap ] as FlxbValueMap)
+
+ buffer.data.withUnsafeBytes { ptr in
+ var ffi_container = InterruptBuffer(data_ptr: ptr.baseAddress!, length: UInt64(ptr.count))
+ withUnsafePointer(to: &ffi_container) { ffi_container_ptr in
+ pax_interrupt(PaxEngineContainer.paxEngineContainer!, ffi_container_ptr)
+ }
+ }
+ } catch {
+ print("Failed to load image data: \(error)")
+ }
+ }
+ }
+
+
+
+ func processNativeMessageQueue(queue: NativeMessageQueue) {
+
+ let buffer = UnsafeBufferPointer(start: queue.data_ptr!, count: Int(queue.length))
+ let root = FlexBuffer.decode(data: Data.init(buffer: buffer))!
+
+ root["messages"]?.asVector?.makeIterator().forEach( { message in
+
+ let textCreateMessage = message["TextCreate"]
+ if textCreateMessage != nil {
+ handleTextCreate(patch: AnyCreatePatch(fb: textCreateMessage!))
+ }
+
+ let textUpdateMessage = message["TextUpdate"]
+ if textUpdateMessage != nil {
+ handleTextUpdate(patch: TextUpdatePatch(fb: textUpdateMessage!))
+ }
+
+ let textDeleteMessage = message["TextDelete"]
+ if textDeleteMessage != nil {
+ handleTextDelete(patch: AnyDeletePatch(fb: textDeleteMessage!))
+ }
+
+ let frameCreateMessage = message["FrameCreate"]
+ if frameCreateMessage != nil {
+ handleFrameCreate(patch: AnyCreatePatch(fb: frameCreateMessage!))
+ }
+
+ let frameUpdateMessage = message["FrameUpdate"]
+ if frameUpdateMessage != nil {
+ handleFrameUpdate(patch: FrameUpdatePatch(fb: frameUpdateMessage!))
+ }
+
+ let frameDeleteMessage = message["FrameDelete"]
+ if frameDeleteMessage != nil {
+ handleFrameDelete(patch: AnyDeletePatch(fb: frameDeleteMessage!))
+ }
+
+ let imageLoadMessage = message["ImageLoad"]
+ if imageLoadMessage != nil {
+ handleImageLoad(patch: ImageLoadPatch(fb: imageLoadMessage!))
+ }
+
+ //^ Add new message-receive handlers here ^
+ })
+
+ }
+
+ }
+}
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Preview Content/Preview Assets.xcassets/Contents.json b/pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Preview Content/Preview Assets.xcassets/Contents.json
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Preview Content/Preview Assets.xcassets/Contents.json
rename to pax-chassis-ios/interface/pax-app-ios/pax-app-ios/Preview Content/Preview Assets.xcassets/Contents.json
diff --git a/pax-chassis-ios/src/lib.rs b/pax-chassis-ios/src/lib.rs
new file mode 100644
index 000000000..f8fbd4464
--- /dev/null
+++ b/pax-chassis-ios/src/lib.rs
@@ -0,0 +1 @@
+pub use pax_chassis_common::core_graphics_c_bridge::*;
\ No newline at end of file
diff --git a/pax-chassis-macos/Cargo.toml b/pax-chassis-macos/Cargo.toml
index f5c5e32d3..10fabf811 100644
--- a/pax-chassis-macos/Cargo.toml
+++ b/pax-chassis-macos/Cargo.toml
@@ -10,11 +10,12 @@ description = "Platform-specific chassis allowing Pax cartridges to be executed
[lib]
name = "paxchassismacos"
-crate-type = ["staticlib", "cdylib"]
+crate-type = ["cdylib"]
[dependencies]
piet = "0.6.0"
piet-coregraphics = "0.6.0"
+pax-chassis-common = { path = "../pax-chassis-common", version="0.9.9" }
pax-core = { path = "../pax-core", version="0.9.9" }
pax-cartridge = {path="../pax-cartridge", version="0.9.9"}
pax-message = {path = "../pax-message", version="0.9.9"}
diff --git a/pax-chassis-macos/README.md b/pax-chassis-macos/README.md
index cd5514a1c..880ddea85 100644
--- a/pax-chassis-macos/README.md
+++ b/pax-chassis-macos/README.md
@@ -9,7 +9,7 @@ Handles:
This directory also includes:
-## pax-dev-harness-macos
+## interface
Simple macOS app for developing Pax projects.
Also usable as a template for packaging full-window Pax apps for macOS
diff --git a/pax-chassis-macos/interface/README.md b/pax-chassis-macos/interface/README.md
new file mode 100644
index 000000000..212c0a075
--- /dev/null
+++ b/pax-chassis-macos/interface/README.md
@@ -0,0 +1,11 @@
+# pax-chassis-macos/interface
+
+Much of the interface for macOS is described in `pax-chassis-common`, and is common across iOS and macOS.
+
+Thus, the interface for pax-chassis-macos includes only the relative complement of (`macOS \ iOS`), namely: a macOS full-app wrapper for a Pax component.
+
+This is useful for local development on a Mac or for publishing full-app Pax-mac projects.
+
+If you wish to use a Pax project as a SwiftUI view inside e.g. an existing Swift project,
+look to the SPM package created inside `pax-chassis-common/pax-swift-cartridge`. That same SPM package
+is consumed by pax-app-macos.
\ No newline at end of file
diff --git a/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.pbxproj b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..3dd779093
--- /dev/null
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.pbxproj
@@ -0,0 +1,564 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 60;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1486C80F2ACE4E48003AB8B8 /* PaxCartridge in Frameworks */ = {isa = PBXBuildFile; productRef = 1486C80E2ACE4E48003AB8B8 /* PaxCartridge */; };
+ 1486C8112ACE4E48003AB8B8 /* PaxCartridgeAssets in Frameworks */ = {isa = PBXBuildFile; productRef = 1486C8102ACE4E48003AB8B8 /* PaxCartridgeAssets */; };
+ 14A8ED632ADE1A7C00292406 /* PaxViewMacos.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14FDCD4A2ACC9D690060F532 /* PaxViewMacos.swift */; };
+ 14A8ED642ADE1A7C00292406 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14FDCD482ACC9D690060F532 /* Main.swift */; };
+ 14A8ED662ADE1A7C00292406 /* Messages in Frameworks */ = {isa = PBXBuildFile; productRef = 14A8ED5D2ADE1A7C00292406 /* Messages */; };
+ 14A8ED672ADE1A7C00292406 /* FlexBuffers in Frameworks */ = {isa = PBXBuildFile; productRef = 14A8ED5C2ADE1A7C00292406 /* FlexBuffers */; };
+ 14A8ED682ADE1A7C00292406 /* PaxCartridge in Frameworks */ = {isa = PBXBuildFile; productRef = 14A8ED5F2ADE1A7C00292406 /* PaxCartridge */; };
+ 14A8ED692ADE1A7C00292406 /* PaxCartridgeAssets in Frameworks */ = {isa = PBXBuildFile; productRef = 14A8ED612ADE1A7C00292406 /* PaxCartridgeAssets */; };
+ 14A8ED6A2ADE1A7C00292406 /* Rendering in Frameworks */ = {isa = PBXBuildFile; productRef = 14A8ED5E2ADE1A7C00292406 /* Rendering */; };
+ 14A8ED6C2ADE1A7C00292406 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14FDCD4F2ACC9D6A0060F532 /* Preview Assets.xcassets */; };
+ 14A8ED6D2ADE1A7C00292406 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14FDCD4C2ACC9D6A0060F532 /* Assets.xcassets */; };
+ 14FDCD492ACC9D690060F532 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14FDCD482ACC9D690060F532 /* Main.swift */; };
+ 14FDCD4B2ACC9D690060F532 /* PaxViewMacos.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14FDCD4A2ACC9D690060F532 /* PaxViewMacos.swift */; };
+ 14FDCD4D2ACC9D6A0060F532 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14FDCD4C2ACC9D6A0060F532 /* Assets.xcassets */; };
+ 14FDCD502ACC9D6A0060F532 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14FDCD4F2ACC9D6A0060F532 /* Preview Assets.xcassets */; };
+ 14FDCD592ACC9E7B0060F532 /* FlexBuffers in Frameworks */ = {isa = PBXBuildFile; productRef = 14FDCD582ACC9E7B0060F532 /* FlexBuffers */; };
+ 14FDCD5B2ACC9E7B0060F532 /* Messages in Frameworks */ = {isa = PBXBuildFile; productRef = 14FDCD5A2ACC9E7B0060F532 /* Messages */; };
+ 14FDCD5D2ACC9E7B0060F532 /* Rendering in Frameworks */ = {isa = PBXBuildFile; productRef = 14FDCD5C2ACC9E7B0060F532 /* Rendering */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 14A8ED712ADE1A7C00292406 /* Pax macOS (Release).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Pax macOS (Release).app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 14FDCD452ACC9D690060F532 /* Pax macOS (Development).app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Pax macOS (Development).app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 14FDCD482ACC9D690060F532 /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = ""; };
+ 14FDCD4A2ACC9D690060F532 /* PaxViewMacos.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaxViewMacos.swift; sourceTree = ""; };
+ 14FDCD4C2ACC9D6A0060F532 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 14FDCD4F2ACC9D6A0060F532 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
+ 14FDCD512ACC9D6A0060F532 /* pax_app_macos.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = pax_app_macos.entitlements; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 14A8ED652ADE1A7C00292406 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 14A8ED662ADE1A7C00292406 /* Messages in Frameworks */,
+ 14A8ED672ADE1A7C00292406 /* FlexBuffers in Frameworks */,
+ 14A8ED682ADE1A7C00292406 /* PaxCartridge in Frameworks */,
+ 14A8ED692ADE1A7C00292406 /* PaxCartridgeAssets in Frameworks */,
+ 14A8ED6A2ADE1A7C00292406 /* Rendering in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 14FDCD422ACC9D690060F532 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 14FDCD5B2ACC9E7B0060F532 /* Messages in Frameworks */,
+ 14FDCD592ACC9E7B0060F532 /* FlexBuffers in Frameworks */,
+ 1486C80F2ACE4E48003AB8B8 /* PaxCartridge in Frameworks */,
+ 1486C8112ACE4E48003AB8B8 /* PaxCartridgeAssets in Frameworks */,
+ 14FDCD5D2ACC9E7B0060F532 /* Rendering in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 1486C80D2ACE4E48003AB8B8 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 14FDCD3C2ACC9D690060F532 = {
+ isa = PBXGroup;
+ children = (
+ 14FDCD472ACC9D690060F532 /* pax-app-macos */,
+ 14FDCD462ACC9D690060F532 /* Products */,
+ 1486C80D2ACE4E48003AB8B8 /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ 14FDCD462ACC9D690060F532 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 14FDCD452ACC9D690060F532 /* Pax macOS (Development).app */,
+ 14A8ED712ADE1A7C00292406 /* Pax macOS (Release).app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 14FDCD472ACC9D690060F532 /* pax-app-macos */ = {
+ isa = PBXGroup;
+ children = (
+ 14FDCD482ACC9D690060F532 /* Main.swift */,
+ 14FDCD4A2ACC9D690060F532 /* PaxViewMacos.swift */,
+ 14FDCD4C2ACC9D6A0060F532 /* Assets.xcassets */,
+ 14FDCD512ACC9D6A0060F532 /* pax_app_macos.entitlements */,
+ 14FDCD4E2ACC9D6A0060F532 /* Preview Content */,
+ );
+ path = "pax-app-macos";
+ sourceTree = "";
+ };
+ 14FDCD4E2ACC9D6A0060F532 /* Preview Content */ = {
+ isa = PBXGroup;
+ children = (
+ 14FDCD4F2ACC9D6A0060F532 /* Preview Assets.xcassets */,
+ );
+ path = "Preview Content";
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 14A8ED5B2ADE1A7C00292406 /* Pax macOS (Release) */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 14A8ED6E2ADE1A7C00292406 /* Build configuration list for PBXNativeTarget "Pax macOS (Release)" */;
+ buildPhases = (
+ 14A8ED622ADE1A7C00292406 /* Sources */,
+ 14A8ED652ADE1A7C00292406 /* Frameworks */,
+ 14A8ED6B2ADE1A7C00292406 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "Pax macOS (Release)";
+ packageProductDependencies = (
+ 14A8ED5C2ADE1A7C00292406 /* FlexBuffers */,
+ 14A8ED5D2ADE1A7C00292406 /* Messages */,
+ 14A8ED5E2ADE1A7C00292406 /* Rendering */,
+ 14A8ED5F2ADE1A7C00292406 /* PaxCartridge */,
+ 14A8ED612ADE1A7C00292406 /* PaxCartridgeAssets */,
+ );
+ productName = "pax-app-macos";
+ productReference = 14A8ED712ADE1A7C00292406 /* Pax macOS (Release).app */;
+ productType = "com.apple.product-type.application";
+ };
+ 14FDCD442ACC9D690060F532 /* Pax macOS (Development) */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 14FDCD542ACC9D6A0060F532 /* Build configuration list for PBXNativeTarget "Pax macOS (Development)" */;
+ buildPhases = (
+ 14FDCD412ACC9D690060F532 /* Sources */,
+ 14FDCD422ACC9D690060F532 /* Frameworks */,
+ 14FDCD432ACC9D690060F532 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "Pax macOS (Development)";
+ packageProductDependencies = (
+ 14FDCD582ACC9E7B0060F532 /* FlexBuffers */,
+ 14FDCD5A2ACC9E7B0060F532 /* Messages */,
+ 14FDCD5C2ACC9E7B0060F532 /* Rendering */,
+ 1486C80E2ACE4E48003AB8B8 /* PaxCartridge */,
+ 1486C8102ACE4E48003AB8B8 /* PaxCartridgeAssets */,
+ );
+ productName = "pax-app-macos";
+ productReference = 14FDCD452ACC9D690060F532 /* Pax macOS (Development).app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 14FDCD3D2ACC9D690060F532 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1500;
+ LastUpgradeCheck = 1500;
+ TargetAttributes = {
+ 14FDCD442ACC9D690060F532 = {
+ CreatedOnToolsVersion = 15.0;
+ };
+ };
+ };
+ buildConfigurationList = 14FDCD402ACC9D690060F532 /* Build configuration list for PBXProject "pax-app-macos" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 14FDCD3C2ACC9D690060F532;
+ packageReferences = (
+ 14FDCD572ACC9E7B0060F532 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-common" */,
+ 14FDCD5E2ACC9EB80060F532 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */,
+ );
+ productRefGroup = 14FDCD462ACC9D690060F532 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 14FDCD442ACC9D690060F532 /* Pax macOS (Development) */,
+ 14A8ED5B2ADE1A7C00292406 /* Pax macOS (Release) */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 14A8ED6B2ADE1A7C00292406 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 14A8ED6C2ADE1A7C00292406 /* Preview Assets.xcassets in Resources */,
+ 14A8ED6D2ADE1A7C00292406 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 14FDCD432ACC9D690060F532 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 14FDCD502ACC9D6A0060F532 /* Preview Assets.xcassets in Resources */,
+ 14FDCD4D2ACC9D6A0060F532 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 14A8ED622ADE1A7C00292406 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 14A8ED632ADE1A7C00292406 /* PaxViewMacos.swift in Sources */,
+ 14A8ED642ADE1A7C00292406 /* Main.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 14FDCD412ACC9D690060F532 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 14FDCD4B2ACC9D690060F532 /* PaxViewMacos.swift in Sources */,
+ 14FDCD492ACC9D690060F532 /* Main.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 14A8ED6F2ADE1A7C00292406 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = "pax-app-macos/pax_app_macos.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"pax-app-macos/Preview Content\"";
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "dev.pax.pax-app-macos";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+ 14A8ED702ADE1A7C00292406 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = "pax-app-macos/pax_app_macos.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"pax-app-macos/Preview Content\"";
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "dev.pax.pax-app-macos";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
+ 14FDCD522ACC9D6A0060F532 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+ 14FDCD532ACC9D6A0060F532 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SDKROOT = macosx;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
+ 14FDCD552ACC9D6A0060F532 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = "pax-app-macos/pax_app_macos.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"pax-app-macos/Preview Content\"";
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "dev.pax.pax-app-macos";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+ 14FDCD562ACC9D6A0060F532 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_ENTITLEMENTS = "pax-app-macos/pax_app_macos.entitlements";
+ CODE_SIGN_STYLE = Automatic;
+ COMBINE_HIDPI_IMAGES = YES;
+ CURRENT_PROJECT_VERSION = 1;
+ DEVELOPMENT_ASSET_PATHS = "\"pax-app-macos/Preview Content\"";
+ ENABLE_PREVIEWS = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/../Frameworks",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 12.0;
+ MARKETING_VERSION = 1.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "dev.pax.pax-app-macos";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 14A8ED6E2ADE1A7C00292406 /* Build configuration list for PBXNativeTarget "Pax macOS (Release)" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 14A8ED6F2ADE1A7C00292406 /* Debug */,
+ 14A8ED702ADE1A7C00292406 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 14FDCD402ACC9D690060F532 /* Build configuration list for PBXProject "pax-app-macos" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 14FDCD522ACC9D6A0060F532 /* Debug */,
+ 14FDCD532ACC9D6A0060F532 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 14FDCD542ACC9D6A0060F532 /* Build configuration list for PBXNativeTarget "Pax macOS (Development)" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 14FDCD552ACC9D6A0060F532 /* Debug */,
+ 14FDCD562ACC9D6A0060F532 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+
+/* Begin XCLocalSwiftPackageReference section */
+ 14A8ED602ADE1A7C00292406 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = "../../../pax-chassis-common/pax-swift-cartridge";
+ };
+ 14FDCD572ACC9E7B0060F532 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-common" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = "../../../pax-chassis-common/pax-swift-common";
+ };
+ 14FDCD5E2ACC9EB80060F532 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = "../../../pax-chassis-common/pax-swift-cartridge";
+ };
+/* End XCLocalSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ 1486C80E2ACE4E48003AB8B8 /* PaxCartridge */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 14FDCD5E2ACC9EB80060F532 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */;
+ productName = PaxCartridge;
+ };
+ 1486C8102ACE4E48003AB8B8 /* PaxCartridgeAssets */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 14FDCD5E2ACC9EB80060F532 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */;
+ productName = PaxCartridgeAssets;
+ };
+ 14A8ED5C2ADE1A7C00292406 /* FlexBuffers */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = FlexBuffers;
+ };
+ 14A8ED5D2ADE1A7C00292406 /* Messages */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = Messages;
+ };
+ 14A8ED5E2ADE1A7C00292406 /* Rendering */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = Rendering;
+ };
+ 14A8ED5F2ADE1A7C00292406 /* PaxCartridge */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 14A8ED602ADE1A7C00292406 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */;
+ productName = PaxCartridge;
+ };
+ 14A8ED612ADE1A7C00292406 /* PaxCartridgeAssets */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = 14A8ED602ADE1A7C00292406 /* XCLocalSwiftPackageReference "../../../pax-chassis-common/pax-swift-cartridge" */;
+ productName = PaxCartridgeAssets;
+ };
+ 14FDCD582ACC9E7B0060F532 /* FlexBuffers */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = FlexBuffers;
+ };
+ 14FDCD5A2ACC9E7B0060F532 /* Messages */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = Messages;
+ };
+ 14FDCD5C2ACC9E7B0060F532 /* Rendering */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = Rendering;
+ };
+/* End XCSwiftPackageProductDependency section */
+ };
+ rootObject = 14FDCD3D2ACC9D690060F532 /* Project object */;
+}
diff --git a/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 000000000..919434a62
--- /dev/null
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Info.plist b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
similarity index 51%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Info.plist
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
index 196a270ce..18d981003 100644
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Info.plist
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -1,12 +1,8 @@
-
-
+
+ IDEDidComputeMac32BitWarning
+
+
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/xcuserdata/zack.xcuserdatad/xcschemes/xcschememanagement.plist b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/xcuserdata/zack.xcuserdatad/xcschemes/xcschememanagement.plist
similarity index 54%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/xcuserdata/zack.xcuserdatad/xcschemes/xcschememanagement.plist
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/xcuserdata/zack.xcuserdatad/xcschemes/xcschememanagement.plist
index 735c82355..f5cb84b2b 100644
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/xcuserdata/zack.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos.xcodeproj/xcuserdata/zack.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -4,23 +4,25 @@
SchemeUserState
- Pax macOS.xcscheme_^#shared#^_
+ Pax macOS (Development) copy.xcscheme_^#shared#^_
+
+ orderHint
+ 1
+
+ Pax macOS (Development).xcscheme_^#shared#^_
orderHint
0
- pax-dev-harness-macos.xcscheme_^#shared#^_
+ debug.xcscheme_^#shared#^_
orderHint
0
-
- SuppressBuildableAutocreation
-
- 14965C0027FE3D0F00A38CA1
+ pax-app-macos.xcscheme_^#shared#^_
- primary
-
+ orderHint
+ 0
diff --git a/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AccentColor.colorset/Contents.json b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 000000000..eb8789700
--- /dev/null
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/Contents.json b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-1024.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-1024.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-1024.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-1024.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-128.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-128.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-128.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-128.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-16.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-16.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-16.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-16.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-256 1.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-256 1.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-256 1.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-256 1.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-256.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-256.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-256.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-256.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-32 1.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-32 1.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-32 1.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-32 1.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-32.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-32.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-32.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-32.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-512 1.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-512 1.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-512 1.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-512 1.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-512.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-512.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-512.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-512.png
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-64.png b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-64.png
similarity index 100%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-64.png
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/AppIcon.appiconset/pax-logo-64.png
diff --git a/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/Contents.json b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/Contents.json
new file mode 100644
index 000000000..73c00596a
--- /dev/null
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Main.swift b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Main.swift
new file mode 100644
index 000000000..61b56bde9
--- /dev/null
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Main.swift
@@ -0,0 +1,17 @@
+//
+// Main.swift
+// pax-app-macos
+//
+// Created by Zack Brown on 10/3/23.
+//
+
+import SwiftUI
+
+@main
+struct pax_app_macosApp: App {
+ var body: some Scene {
+ WindowGroup {
+ PaxViewMacos()
+ }
+ }
+}
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/PaxView.swift b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/PaxViewMacos.swift
similarity index 70%
rename from pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/PaxView.swift
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/PaxViewMacos.swift
index 46feb310e..e493a0352 100644
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/PaxView.swift
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/PaxViewMacos.swift
@@ -1,43 +1,19 @@
//
// ContentView.swift
-// pax-dev-harness-macos
+// interface
//
// Created by Zachary Brown on 4/6/22.
//
import SwiftUI
import Foundation
+import FlexBuffers
+import Messages
+import Rendering
+import PaxCartridgeAssets
+import PaxCartridge
-class TextElements: ObservableObject {
- static let singleton : TextElements = TextElements()
-
- @Published var elements : [[UInt64]: TextElement] = [:]
-
- func add(element: TextElement) {
- self.elements[element.id_chain] = element
- }
- func remove(id: [UInt64]) {
- self.elements.removeValue(forKey: id)
- }
-}
-
-class FrameElements: ObservableObject {
- static let singleton : FrameElements = FrameElements()
-
- @Published var elements : [[UInt64]: FrameElement] = [:]
-
- func add(element: FrameElement) {
- self.elements[element.id_chain] = element
- }
- func remove(id: [UInt64]) {
- self.elements.removeValue(forKey: id)
- }
- func get(id: [UInt64]) -> FrameElement? {
- return self.elements[id]
- }
-}
-
-struct PaxView: View {
+struct PaxViewMacos: View {
var canvasView : some View = PaxCanvasViewRepresentable()
.frame(minWidth: 300, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
@@ -52,22 +28,28 @@ struct PaxView: View {
}.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .global).onEnded { dragGesture in
//FUTURE: especially if parsing is a bottleneck, could use a different encoding than JSON
let json = String(format: "{\"Click\": {\"x\": %f, \"y\": %f, \"button\": \"Left\", \"modifiers\":[] } }", dragGesture.location.x, dragGesture.location.y);
- let buffer = try! FlexBufferBuilder.fromJSON(json)
+ let buffer = try! FlexBufferBuilder.fromJSON(json)
- //Send `Click` interrupt
- buffer.data.withUnsafeBytes({ptr in
- var ffi_container = InterruptBuffer( data_ptr: ptr.baseAddress!, length: UInt64(ptr.count) )
+ //Send `Click` interrupt
+ buffer.data.withUnsafeBytes({ptr in
+ var ffi_container = InterruptBuffer( data_ptr: ptr.baseAddress!, length: UInt64(ptr.count) )
- withUnsafePointer(to: &ffi_container) {ffi_container_ptr in
- pax_interrupt(PaxEngineContainer.paxEngineContainer!, ffi_container_ptr)
- }
- })
+ withUnsafePointer(to: &ffi_container) {ffi_container_ptr in
+ pax_interrupt(PaxEngineContainer.paxEngineContainer!, ffi_container_ptr)
+ }
+ })
})
}
func registerFonts() {
- guard let resourceURL = Bundle.main.resourceURL else { return }
+
+ let nestedBundleURL = Bundle.main.url(forResource: "PaxSwiftCartridge_PaxCartridgeAssets", withExtension: "bundle")!
+
+ let resourceBundle = Bundle(url: nestedBundleURL)!
+
+ let resourceURL = resourceBundle.resourceURL!
+
let fontFileExtensions = ["ttf", "otf"]
do {
@@ -96,110 +78,25 @@ struct PaxView: View {
}
-
-
class PaxEngineContainer {
static var paxEngineContainer : OpaquePointer? = nil
}
- struct NativeRenderingLayer: View {
-
- @ObservedObject var textElements : TextElements = TextElements.singleton
- @ObservedObject var frameElements : FrameElements = FrameElements.singleton
-
- func getClippingMask(clippingIds: [[UInt64]]) -> some View {
-
- var elements : [FrameElement] = []
-
- clippingIds.makeIterator().forEach( { id_chain in
- elements.insert(self.frameElements.elements[id_chain]!, at: 0)
- })
-
- return ZStack { ForEach(elements, id: \.id_chain) { frameElement in
- Rectangle()
- .frame(width: CGFloat(frameElement.size_x), height: CGFloat(frameElement.size_y))
- .position(x: CGFloat(frameElement.size_x / 2.0), y: CGFloat(frameElement.size_y / 2.0))
- .transformEffect(CGAffineTransform.init(
- a: CGFloat(frameElement.transform[0]),
- b: CGFloat(frameElement.transform[1]),
- c: CGFloat(frameElement.transform[2]),
- d: CGFloat(frameElement.transform[3]),
- tx: CGFloat(frameElement.transform[4]),
- ty: CGFloat(frameElement.transform[5]))
- )
- } }
- }
-
- @ViewBuilder
- func getPositionedTextGroup(textElement: TextElement) -> some View {
- let transform = CGAffineTransform.init(
- a: CGFloat(textElement.transform[0]),
- b: CGFloat(textElement.transform[1]),
- c: CGFloat(textElement.transform[2]),
- d: CGFloat(textElement.transform[3]),
- tx: CGFloat(textElement.transform[4]),
- ty: CGFloat(textElement.transform[5])
- )
- var text: AttributedString {
- var attributedString: AttributedString = try! AttributedString(markdown: textElement.content, options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace))
-
- for run in attributedString.runs {
- if run.link != nil {
- if let linkStyle = textElement.style_link {
- attributedString[run.range].font = linkStyle.font.getFont(size: linkStyle.font_size)
- if(linkStyle.underline){
- attributedString[run.range].underlineStyle = .single
- } else {
- attributedString[run.range].underlineStyle = .none
- }
- attributedString[run.range].foregroundColor = linkStyle.fill
- }
- }
- }
- return attributedString
-
- }
- let textView : some View =
- Text(text)
- .foregroundColor(textElement.textStyle.fill)
- .font(textElement.textStyle.font.getFont(size: textElement.textStyle.font_size))
- .frame(width: CGFloat(textElement.size_x), height: CGFloat(textElement.size_y), alignment: textElement.textStyle.alignment)
- .position(x: CGFloat(textElement.size_x / 2.0), y: CGFloat(textElement.size_y / 2.0))
- .transformEffect(transform)
- .textSelection(.enabled)
-
-//
-// if !textElement.clipping_ids.isEmpty {
-// textView.mask(getClippingMask(clippingIds: textElement.clipping_ids))
-// } else {
-// textView
-// }
- textView
- }
-
- var body: some View {
- ZStack{
- ForEach(Array(self.textElements.elements.values), id: \.id_chain) { textElement in
- getPositionedTextGroup(textElement: textElement)
- }
- }
-
- }
- }
+
struct PaxCanvasViewRepresentable: NSViewRepresentable {
- typealias NSViewType = PaxCanvasView
+ typealias NSViewType = PaxCanvasViewMacos
- func makeNSView(context: Context) -> PaxCanvasView {
- let view = PaxCanvasView()
+ func makeNSView(context: Context) -> PaxCanvasViewMacos {
+ let view = PaxCanvasViewMacos()
return view
}
- func updateNSView(_ canvas: PaxCanvasView, context: Context) { }
+ func updateNSView(_ canvas: PaxCanvasViewMacos, context: Context) { }
}
- class PaxCanvasView: NSView {
+ class PaxCanvasViewMacos: NSView {
@ObservedObject var textElements = TextElements.singleton
@ObservedObject var frameElements = FrameElements.singleton
@@ -207,6 +104,8 @@ struct PaxView: View {
private var displayLink: CVDisplayLink?
override init(frame frameRect: NSRect) {
+
+
super.init(frame: frameRect)
self.wantsLayer = true
self.layer?.drawsAsynchronously = true
@@ -344,17 +243,23 @@ struct PaxView: View {
func handleImageLoad(patch: ImageLoadPatch) {
Task {
do {
- let path = patch.path!
- let url = URL(fileURLWithPath: path)
+ let fullPatchPath = patch.path!
+ let url = URL(fileURLWithPath: fullPatchPath)
let fileNameWithExtension = url.lastPathComponent
let fileExtension = url.pathExtension
let fileName = String(fileNameWithExtension.prefix(fileNameWithExtension.count - fileExtension.count - 1))
- guard let bundleURL = Bundle.main.url(forResource: fileName, withExtension: fileExtension) else {
- throw NSError(domain: "", code: 100, userInfo: [NSLocalizedDescriptionKey : "Image file not found in bundle"])
+ guard let nestedBundleURL = Bundle.main.url(forResource: "PaxSwiftCartridge_PaxCartridgeAssets", withExtension: "bundle") else {
+ throw NSError(domain: "", code: 99, userInfo: [NSLocalizedDescriptionKey : "PaxCartridgeAssets bundle not found in main bundle. Make sure you have imported PaxCartridgeAssets in Swift."])
+ }
+
+ let assetsBundle = Bundle(url: nestedBundleURL)
+
+ guard let imageURL = assetsBundle?.url(forResource: fileName, withExtension: fileExtension) else {
+ throw NSError(domain: "", code: 100, userInfo: [NSLocalizedDescriptionKey : "Image file not found in nested bundle"])
}
- guard let image = NSImage(contentsOf: bundleURL) else {
+ guard let image = NSImage(contentsOf: imageURL) else {
throw NSError(domain: "", code: 101, userInfo: [NSLocalizedDescriptionKey : "Could not create NSImage from data"])
}
diff --git a/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Preview Content/Preview Assets.xcassets/Contents.json b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 000000000..73c00596a
--- /dev/null
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/pax-chassis-macos/pax-dev-harness-macos/Pax macOSDebug.entitlements b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/pax_app_macos.entitlements
similarity index 63%
rename from pax-chassis-macos/pax-dev-harness-macos/Pax macOSDebug.entitlements
rename to pax-chassis-macos/interface/pax-app-macos/pax-app-macos/pax_app_macos.entitlements
index 71a0adc2c..18aff0ce4 100644
--- a/pax-chassis-macos/pax-dev-harness-macos/Pax macOSDebug.entitlements
+++ b/pax-chassis-macos/interface/pax-app-macos/pax-app-macos/pax_app_macos.entitlements
@@ -4,13 +4,7 @@
com.apple.security.app-sandbox
- com.apple.security.cs.disable-library-validation
-
com.apple.security.files.user-selected.read-only
- com.apple.security.network.client
-
- com.apple.security.network.server
-
diff --git a/pax-chassis-macos/pax-dev-harness-macos/Paxchassismacos-Bridging-Header.h b/pax-chassis-macos/pax-dev-harness-macos/Paxchassismacos-Bridging-Header.h
deleted file mode 100644
index 4072196e6..000000000
--- a/pax-chassis-macos/pax-dev-harness-macos/Paxchassismacos-Bridging-Header.h
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-// Paxchassismacos-Bridging-Header.h
-// pax-dev-harness-macos
-//
-// Created by Zachary Brown on 4/12/22.
-//
-
-#ifndef Paxchassismacos_Bridging_Header_h
-#define Paxchassismacos_Bridging_Header_h
-
-#import "paxchassismacos.h"
-
-#endif /* Paxchassismacos_Bridging_Header_h */
-
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/project.pbxproj b/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/project.pbxproj
deleted file mode 100644
index 73991fe3d..000000000
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,466 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 55;
- objects = {
-
-/* Begin PBXBuildFile section */
- 140C6AF92825C99C003BACE3 /* FlexBufferBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140C6AF62825C99B003BACE3 /* FlexBufferBuilder.swift */; };
- 140C6AFA2825C99C003BACE3 /* FlexBuffers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140C6AF72825C99B003BACE3 /* FlexBuffers.swift */; };
- 140C6AFE28276BCD003BACE3 /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 140C6AFD28276BCD003BACE3 /* Messages.swift */; };
- 1459D7E4280F2922006391F8 /* libpaxchassismacos.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1459D7E1280F2902006391F8 /* libpaxchassismacos.dylib */; };
- 1459D7E5280F2922006391F8 /* libpaxchassismacos.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 1459D7E1280F2902006391F8 /* libpaxchassismacos.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
- 1459D7E8280F2933006391F8 /* libpaxchassismacos.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1459D7E7280F2922006391F8 /* libpaxchassismacos.a */; };
- 14965C0527FE3D0F00A38CA1 /* Main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14965C0427FE3D0F00A38CA1 /* Main.swift */; };
- 14965C0727FE3D0F00A38CA1 /* PaxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 14965C0627FE3D0F00A38CA1 /* PaxView.swift */; };
- 14965C0927FE3D1100A38CA1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14965C0827FE3D1100A38CA1 /* Assets.xcassets */; };
- 14965C0C27FE3D1100A38CA1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 14965C0B27FE3D1100A38CA1 /* Preview Assets.xcassets */; };
- 14965C1E2805EAFD00A38CA1 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 14965C1D2805EAF500A38CA1 /* libresolv.tbd */; platformFilter = maccatalyst; };
-/* End PBXBuildFile section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 1459D7E6280F2922006391F8 /* Embed Libraries */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 10;
- files = (
- 1459D7E5280F2922006391F8 /* libpaxchassismacos.dylib in Embed Libraries */,
- );
- name = "Embed Libraries";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 140C6AF62825C99B003BACE3 /* FlexBufferBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexBufferBuilder.swift; sourceTree = ""; };
- 140C6AF72825C99B003BACE3 /* FlexBuffers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FlexBuffers.swift; sourceTree = ""; };
- 140C6AF82825C99C003BACE3 /* FlexBuffers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FlexBuffers.h; sourceTree = ""; };
- 140C6AFD28276BCD003BACE3 /* Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Messages.swift; sourceTree = ""; };
- 1459D7E1280F2902006391F8 /* libpaxchassismacos.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpaxchassismacos.dylib; path = ../target/debug/libpaxchassismacos.dylib; sourceTree = ""; };
- 1459D7E7280F2922006391F8 /* libpaxchassismacos.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpaxchassismacos.a; path = ../target/debug/libpaxchassismacos.a; sourceTree = ""; };
- 14619AC429C505180024805D /* Pax macOSDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "Pax macOSDebug.entitlements"; sourceTree = ""; };
- 14965C0127FE3D0F00A38CA1 /* Pax macOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Pax macOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
- 14965C0427FE3D0F00A38CA1 /* Main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Main.swift; sourceTree = ""; };
- 14965C0627FE3D0F00A38CA1 /* PaxView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaxView.swift; sourceTree = ""; };
- 14965C0827FE3D1100A38CA1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
- 14965C0B27FE3D1100A38CA1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
- 14965C0D27FE3D1100A38CA1 /* pax_dev_harness_macos.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = pax_dev_harness_macos.entitlements; sourceTree = ""; };
- 14965C142805E47D00A38CA1 /* src */ = {isa = PBXFileReference; lastKnownFileType = folder; name = src; path = ../src; sourceTree = ""; };
- 14965C152805E4BF00A38CA1 /* paxchassismacos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = paxchassismacos.h; path = ../src/paxchassismacos.h; sourceTree = ""; };
- 14965C162805E4EF00A38CA1 /* Paxchassismacos-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Paxchassismacos-Bridging-Header.h"; sourceTree = ""; };
- 14965C172805EA3B00A38CA1 /* libpaxchassismacos.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libpaxchassismacos.a; path = ../../target/release/libpaxchassismacos.a; sourceTree = ""; };
- 14965C192805EAA700A38CA1 /* libpaxchassismacos.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpaxchassismacos.dylib; path = ../../target/release/libpaxchassismacos.dylib; sourceTree = ""; };
- 14965C1D2805EAF500A38CA1 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 14965BFE27FE3D0F00A38CA1 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 1459D7E8280F2933006391F8 /* libpaxchassismacos.a in Frameworks */,
- 14965C1E2805EAFD00A38CA1 /* libresolv.tbd in Frameworks */,
- 1459D7E4280F2922006391F8 /* libpaxchassismacos.dylib in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 140C6AFB28276B89003BACE3 /* FlexBuffers */ = {
- isa = PBXGroup;
- children = (
- 140C6AF62825C99B003BACE3 /* FlexBufferBuilder.swift */,
- 140C6AF82825C99C003BACE3 /* FlexBuffers.h */,
- 140C6AF72825C99B003BACE3 /* FlexBuffers.swift */,
- );
- path = FlexBuffers;
- sourceTree = "";
- };
- 14965BF827FE3D0F00A38CA1 = {
- isa = PBXGroup;
- children = (
- 14619AC429C505180024805D /* Pax macOSDebug.entitlements */,
- 14965C162805E4EF00A38CA1 /* Paxchassismacos-Bridging-Header.h */,
- 14965C152805E4BF00A38CA1 /* paxchassismacos.h */,
- 14965C0327FE3D0F00A38CA1 /* pax-dev-harness-macos */,
- 14965C0227FE3D0F00A38CA1 /* Products */,
- 14965C132805E47D00A38CA1 /* Frameworks */,
- );
- sourceTree = "";
- };
- 14965C0227FE3D0F00A38CA1 /* Products */ = {
- isa = PBXGroup;
- children = (
- 14965C0127FE3D0F00A38CA1 /* Pax macOS.app */,
- );
- name = Products;
- sourceTree = "";
- };
- 14965C0327FE3D0F00A38CA1 /* pax-dev-harness-macos */ = {
- isa = PBXGroup;
- children = (
- 140C6AFB28276B89003BACE3 /* FlexBuffers */,
- 14965C0427FE3D0F00A38CA1 /* Main.swift */,
- 140C6AFD28276BCD003BACE3 /* Messages.swift */,
- 14965C0627FE3D0F00A38CA1 /* PaxView.swift */,
- 14965C0827FE3D1100A38CA1 /* Assets.xcassets */,
- 14965C0D27FE3D1100A38CA1 /* pax_dev_harness_macos.entitlements */,
- 14965C0A27FE3D1100A38CA1 /* Preview Content */,
- );
- path = "pax-dev-harness-macos";
- sourceTree = "";
- };
- 14965C0A27FE3D1100A38CA1 /* Preview Content */ = {
- isa = PBXGroup;
- children = (
- 14965C0B27FE3D1100A38CA1 /* Preview Assets.xcassets */,
- );
- path = "Preview Content";
- sourceTree = "";
- };
- 14965C132805E47D00A38CA1 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 1459D7E7280F2922006391F8 /* libpaxchassismacos.a */,
- 1459D7E1280F2902006391F8 /* libpaxchassismacos.dylib */,
- 14965C1D2805EAF500A38CA1 /* libresolv.tbd */,
- 14965C192805EAA700A38CA1 /* libpaxchassismacos.dylib */,
- 14965C172805EA3B00A38CA1 /* libpaxchassismacos.a */,
- 14965C142805E47D00A38CA1 /* src */,
- );
- name = Frameworks;
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 14965C0027FE3D0F00A38CA1 /* Pax macOS */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 14965C1027FE3D1100A38CA1 /* Build configuration list for PBXNativeTarget "Pax macOS" */;
- buildPhases = (
- 14965BFD27FE3D0F00A38CA1 /* Sources */,
- 14965BFE27FE3D0F00A38CA1 /* Frameworks */,
- 14965BFF27FE3D0F00A38CA1 /* Resources */,
- 1459D7E6280F2922006391F8 /* Embed Libraries */,
- D082094129FE19DD006C5651 /* Copy Font & Image Files */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "Pax macOS";
- packageProductDependencies = (
- );
- productName = "pax-dev-harness-macos";
- productReference = 14965C0127FE3D0F00A38CA1 /* Pax macOS.app */;
- productType = "com.apple.product-type.application";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 14965BF927FE3D0F00A38CA1 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- BuildIndependentTargetsInParallel = 1;
- LastSwiftUpdateCheck = 1300;
- LastUpgradeCheck = 1430;
- TargetAttributes = {
- 14965C0027FE3D0F00A38CA1 = {
- CreatedOnToolsVersion = 13.0;
- };
- };
- };
- buildConfigurationList = 14965BFC27FE3D0F00A38CA1 /* Build configuration list for PBXProject "pax-dev-harness-macos" */;
- compatibilityVersion = "Xcode 13.0";
- developmentRegion = en;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 14965BF827FE3D0F00A38CA1;
- packageReferences = (
- );
- productRefGroup = 14965C0227FE3D0F00A38CA1 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 14965C0027FE3D0F00A38CA1 /* Pax macOS */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 14965BFF27FE3D0F00A38CA1 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 14965C0C27FE3D1100A38CA1 /* Preview Assets.xcassets in Resources */,
- 14965C0927FE3D1100A38CA1 /* Assets.xcassets in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- D082094129FE19DD006C5651 /* Copy Font & Image Files */ = {
- isa = PBXShellScriptBuildPhase;
- alwaysOutOfDate = 1;
- buildActionMask = 12;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- );
- name = "Copy Font & Image Files";
- outputFileListPaths = (
- );
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "# Define the target folder for resources\nRESOURCES_PATH=\"$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH\"\n\n# Find the .pax folder\nPAX_FOLDER_DIR=$(find ../../../../../../ -type d -name \"*.pax\" -print -quit)\n\n# Get the parent directory of the .pax folder\nPAX_PARENT_DIR=$(dirname \"$PAX_FOLDER_DIR\")\n\n# Find the assets folder on the same level as the .pax folder\nASSETS_TARGET_DIR=$(find \"$PAX_PARENT_DIR\" -maxdepth 1 -type d -name \"assets\" -print -quit)\necho \"Copying assets from: $ASSETS_TARGET_DIR to: $RESOURCES_PATH\"\n\n# Copy all the files recursively if the ASSETS_TARGET_DIR is found\nif [ -d \"$ASSETS_TARGET_DIR\" ]; then\n # Using find to locate and copy files including the directory structure\n for ext in ttf otf jpg png gif tif bmp svg; do\n find \"$ASSETS_TARGET_DIR\" -name \"*.$ext\" -exec cp {} \"$RESOURCES_PATH\" \\;\n done\nelse\n echo \"WARNING: ASSETS_TARGET_DIR not found! Skipping assets copy.\"\nfi\n";
- showEnvVarsInLog = 0;
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 14965BFD27FE3D0F00A38CA1 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 140C6AFA2825C99C003BACE3 /* FlexBuffers.swift in Sources */,
- 14965C0727FE3D0F00A38CA1 /* PaxView.swift in Sources */,
- 140C6AFE28276BCD003BACE3 /* Messages.swift in Sources */,
- 14965C0527FE3D0F00A38CA1 /* Main.swift in Sources */,
- 140C6AF92825C99C003BACE3 /* FlexBufferBuilder.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 14965C0E27FE3D1100A38CA1 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
- CLANG_CXX_LIBRARY = "";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_IDENTITY = "";
- COPY_PHASE_STRIP = NO;
- DEAD_CODE_STRIPPING = YES;
- DEBUG_INFORMATION_FORMAT = dwarf;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- EXCLUDED_ARCHS = "";
- GCC_C_LANGUAGE_STANDARD = "compiler-default";
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 13.3;
- MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
- MTL_FAST_MATH = YES;
- NEW_SETTING = "";
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = macosx;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- };
- name = Debug;
- };
- 14965C0F27FE3D1100A38CA1 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_ANALYZER_NONNULL = YES;
- CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
- CLANG_CXX_LANGUAGE_STANDARD = "compiler-default";
- CLANG_CXX_LIBRARY = "";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_ENABLE_OBJC_WEAK = YES;
- CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_COMMA = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
- CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
- CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
- CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
- CLANG_WARN_STRICT_PROTOTYPES = YES;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- CODE_SIGN_IDENTITY = "";
- COPY_PHASE_STRIP = NO;
- DEAD_CODE_STRIPPING = YES;
- DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- EXCLUDED_ARCHS = "";
- GCC_C_LANGUAGE_STANDARD = "compiler-default";
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 13.3;
- MTL_ENABLE_DEBUG_INFO = NO;
- MTL_FAST_MATH = YES;
- NEW_SETTING = "";
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = macosx;
- SWIFT_COMPILATION_MODE = wholemodule;
- SWIFT_OPTIMIZATION_LEVEL = "-O";
- };
- name = Release;
- };
- 14965C1127FE3D1100A38CA1 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CODE_SIGN_ENTITLEMENTS = "Pax macOSDebug.entitlements";
- CODE_SIGN_IDENTITY = "Apple Development";
- "CODE_SIGN_IDENTITY[sdk=macosx*]" = "";
- CODE_SIGN_STYLE = Manual;
- COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 1;
- DEAD_CODE_STRIPPING = YES;
- DEVELOPMENT_ASSET_PATHS = "\"pax-dev-harness-macos/Preview Content\"";
- DEVELOPMENT_TEAM = "";
- ENABLE_HARDENED_RUNTIME = NO;
- ENABLE_PREVIEWS = YES;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_NSHumanReadableCopyright = "";
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- );
- LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/../target/debug";
- MACOSX_DEPLOYMENT_TARGET = 13.3;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = "org.pax-lang.pax-dev-harness-macos";
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE_SPECIFIER = "";
- SDKROOT = macosx13.3;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/Paxchassismacos-Bridging-Header.h";
- SWIFT_VERSION = 5.0;
- };
- name = Debug;
- };
- 14965C1227FE3D1100A38CA1 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
- CODE_SIGN_ENTITLEMENTS = "pax-dev-harness-macos/pax_dev_harness_macos.entitlements";
- CODE_SIGN_IDENTITY = "";
- "CODE_SIGN_IDENTITY[sdk=macosx*]" = "";
- CODE_SIGN_STYLE = Manual;
- COMBINE_HIDPI_IMAGES = YES;
- CURRENT_PROJECT_VERSION = 1;
- DEAD_CODE_STRIPPING = YES;
- DEVELOPMENT_ASSET_PATHS = "\"pax-dev-harness-macos/Preview Content\"";
- DEVELOPMENT_TEAM = "";
- ENABLE_HARDENED_RUNTIME = NO;
- ENABLE_PREVIEWS = YES;
- GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_NSHumanReadableCopyright = "";
- LD_RUNPATH_SEARCH_PATHS = (
- "$(inherited)",
- "@executable_path/../Frameworks",
- );
- LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/../target/debug";
- MACOSX_DEPLOYMENT_TARGET = 13.3;
- MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = "org.pax-lang.pax-dev-harness-macos";
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE_SPECIFIER = "";
- SDKROOT = macosx13.3;
- SWIFT_EMIT_LOC_STRINGS = YES;
- SWIFT_OBJC_BRIDGING_HEADER = "$(PROJECT_DIR)/Paxchassismacos-Bridging-Header.h";
- SWIFT_VERSION = 5.0;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 14965BFC27FE3D0F00A38CA1 /* Build configuration list for PBXProject "pax-dev-harness-macos" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 14965C0E27FE3D1100A38CA1 /* Debug */,
- 14965C0F27FE3D1100A38CA1 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 14965C1027FE3D1100A38CA1 /* Build configuration list for PBXNativeTarget "Pax macOS" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 14965C1127FE3D1100A38CA1 /* Debug */,
- 14965C1227FE3D1100A38CA1 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 14965BF927FE3D0F00A38CA1 /* Project object */;
-}
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/xcshareddata/xcschemes/Pax macOS.xcscheme b/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/xcshareddata/xcschemes/Pax macOS.xcscheme
deleted file mode 100644
index 35a038d92..000000000
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos.xcodeproj/xcshareddata/xcschemes/Pax macOS.xcscheme
+++ /dev/null
@@ -1,78 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Main.swift b/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Main.swift
deleted file mode 100644
index 5f464a332..000000000
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/Main.swift
+++ /dev/null
@@ -1,17 +0,0 @@
-//
-// Main.swift
-// pax-dev-harness-macos
-//
-// Created by Zachary Brown on 4/6/22.
-//
-
-import SwiftUI
-
-@main
-struct pax_dev_harness_macosApp: App {
- var body: some Scene {
- WindowGroup {
- PaxView()
- }
- }
-}
diff --git a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/pax_dev_harness_macos.entitlements b/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/pax_dev_harness_macos.entitlements
deleted file mode 100644
index 71a0adc2c..000000000
--- a/pax-chassis-macos/pax-dev-harness-macos/pax-dev-harness-macos/pax_dev_harness_macos.entitlements
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
- com.apple.security.app-sandbox
-
- com.apple.security.cs.disable-library-validation
-
- com.apple.security.files.user-selected.read-only
-
- com.apple.security.network.client
-
- com.apple.security.network.server
-
-
-
diff --git a/pax-chassis-macos/pax-dev-harness-macos/run-debuggable-mac-app.sh b/pax-chassis-macos/pax-dev-harness-macos/run-debuggable-mac-app.sh
deleted file mode 100755
index a0435d793..000000000
--- a/pax-chassis-macos/pax-dev-harness-macos/run-debuggable-mac-app.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/bash
-
-# Expects args:
-# 1: VERBOSE ∈ {"true" , "false"}
-# 2: EXCLUDE_ARCHS ∈ {"arm64" , "x86_64"}
-# 3: SHOULD_ALSO_RUN ∈ {"true" , "false"}
-# 4: OUTPUT_PATH : output directory for build
-VERBOSE=$1
-EXCLUDE_ARCHS=$2
-SHOULD_ALSO_RUN=$3
-OUTPUT_PATH=$4
-
-runbuild () {
- xcodebuild archive \
- -configuration Debug \
- -scheme "Pax macOS" \
- -archivePath build/PaxDevHarnessMacos.xcarchive \
- -sdk macosx13.3 \
- SKIP_INSTALL=NO SUPPORTS_MACCATALYST=YES ONLY_ACTIVE_ARCH=YES EXCLUDED_ARCHS="$EXCLUDE_ARCHS"
-}
-
-# Build
-if [ "$VERBOSE" == "true" ]; then
- # Pipe output to both stdout and stderr
- runbuild 2>&1
-else
- # Pipe stdout to /dev/null, but pipe stderr to /dev/stderr
- runbuild > /dev/null 2>&1 >&2
-fi
-
-# Clear old build and move to output directory
-rm -rf "$OUTPUT_PATH"
-mkdir -p "$OUTPUT_PATH"
-cp -r "build/PaxDevHarnessMacos.xcarchive/Products/Applications/Pax macOS.app" "$OUTPUT_PATH"
-cd "$OUTPUT_PATH"
-
-if [ "$SHOULD_ALSO_RUN" == "true" ]; then
- # Run
- Pax\ macOS.app/Contents/MacOS/Pax\ macOS
-fi
\ No newline at end of file
diff --git a/pax-chassis-macos/src/lib.rs b/pax-chassis-macos/src/lib.rs
index e6d21ce13..8d4e0df61 100644
--- a/pax-chassis-macos/src/lib.rs
+++ b/pax-chassis-macos/src/lib.rs
@@ -1,212 +1,2 @@
-#![allow(non_snake_case)] //Non-snake-case is used here to help denote foreign structs, e.g. from Swift via C
-extern crate core;
-
-use std::cell::RefCell;
-use std::collections::HashMap;
-use std::ffi::c_void;
-use std::rc::Rc;
-
-use std::mem::{transmute, ManuallyDrop};
-use std::os::raw::c_char;
-
-use core_graphics::context::CGContext;
-use piet_coregraphics::CoreGraphicsContext;
-
-use flexbuffers;
-use flexbuffers::DeserializationError;
-use serde::Serialize;
-
-use pax_cartridge;
-use pax_core::{InstanceRegistry, PaxEngine};
-
-//Re-export all native message types; used by Swift via FFI.
-//Note that any types exposed by pax_message must ALSO be added to `paxchassismacos.h`
-//in order to be visible to Swift
-pub use pax_message::*;
-use pax_runtime_api::{ArgsClick, ArgsScroll, ModifierKey, MouseButton, MouseEventArgs};
-
-/// Container data structure for PaxEngine, aggregated to support passing across C bridge
-#[repr(C)] //Exposed to Swift via paxchassismacos.h
-pub struct PaxEngineContainer {
- _engine: *mut PaxEngine>,
- //NOTE: since that has become a single field, this data structure may be be retired and `*mut PaxEngine` could be passed directly.
-}
-
-/// Allocate an instance of the Pax engine, with a specified root/main component from the loaded `pax_cartridge`.
-#[no_mangle] //Exposed to Swift via paxchassismacos.h
-pub extern "C" fn pax_init(logger: extern "C" fn(*const c_char)) -> *mut PaxEngineContainer {
- //Initialize a ManuallyDrop-contained PaxEngine, so that a pointer to that
- //engine can be passed back to Swift via the C (FFI) bridge
- //This could presumably be cleaned up -- see `pax_dealloc_engine`
- let instance_registry: Rc>>> =
- Rc::new(RefCell::new(InstanceRegistry::new()));
- let main_component_instance =
- pax_cartridge::instantiate_main_component(Rc::clone(&instance_registry));
- let expression_table = pax_cartridge::instantiate_expression_table();
-
- let engine: ManuallyDrop>>> =
- ManuallyDrop::new(Box::new(PaxEngine::new(
- main_component_instance,
- expression_table,
- pax_runtime_api::PlatformSpecificLogger::MacOS(logger),
- (1.0, 1.0),
- instance_registry,
- )));
-
- let container = ManuallyDrop::new(Box::new(PaxEngineContainer {
- _engine: Box::into_raw(ManuallyDrop::into_inner(engine)),
- }));
-
- Box::into_raw(ManuallyDrop::into_inner(container))
-}
-
-/// Destroy `engine` and clean up the `ManuallyDrop` container surround it.
-#[no_mangle]
-pub extern "C" fn pax_dealloc_engine(_container: *mut PaxEngineContainer) {
- //particularly for when we need to support elegant clean-up from attached harness
- unimplemented!();
-}
-
-/// Send `interrupt`s from the chassis, for example: user input
-/// Note that in any single-threaded environemnt, these interrupts will happen
-/// synchronously between engine ticks, allowing for safe unwrapping / borrowing
-/// of engine and runtime here. In short: this happens between ticks.
-#[no_mangle]
-pub extern "C" fn pax_interrupt(
- engine_container: *mut PaxEngineContainer,
- buffer: *const InterruptBuffer,
-) {
- let mut engine = unsafe { Box::from_raw((*engine_container)._engine) };
- // let slice = unsafe { buffer.as_ref().unwrap() };
-
- let length: u64 = unsafe {
- (*buffer).length.try_into().unwrap() // length negative or overflowed
- };
-
- let slice = unsafe {
- if (*buffer).data_ptr.is_null() {
- &mut []
- } else {
- std::slice::from_raw_parts((*buffer).data_ptr, length.try_into().unwrap())
- }
- };
-
- let interrupt_wrapped: Result =
- flexbuffers::from_slice(slice);
- let interrupt = interrupt_wrapped.unwrap();
- match interrupt {
- NativeInterrupt::Click(args) => {
- let prospective_hit = engine.get_topmost_element_beneath_ray((args.x, args.y));
- match prospective_hit {
- Some(topmost_node) => {
- let modifiers = args
- .modifiers
- .iter()
- .map(|x| ModifierKey::from(x))
- .collect();
- let args_click = ArgsClick {
- mouse: MouseEventArgs {
- x: args.x,
- y: args.y,
- button: MouseButton::from(args.button),
- modifiers,
- },
- };
- topmost_node.dispatch_click(args_click);
- }
- _ => {}
- };
- }
-
- NativeInterrupt::Scroll(args) => {
- let prospective_hit = engine.get_focused_element();
- match prospective_hit {
- Some(topmost_node) => {
- let args_scroll = ArgsScroll {
- delta_x: args.delta_x,
- delta_y: args.delta_y,
- };
- topmost_node.dispatch_scroll(args_scroll);
- }
- _ => {}
- };
- }
- NativeInterrupt::Image(args) => match args {
- ImageLoadInterruptArgs::Reference(ref_args) => {
- let ptr = ref_args.image_data as *const u8;
- let slice = unsafe { std::slice::from_raw_parts(ptr, ref_args.image_data_length) };
- let owned_data: Vec = slice.to_vec();
- engine.load_image(
- ref_args.id_chain,
- owned_data,
- ref_args.width,
- ref_args.height,
- );
- }
- ImageLoadInterruptArgs::Data(_) => {}
- },
- _ => {}
- }
-
- unsafe { (*engine_container)._engine = Box::into_raw(engine) };
-}
-
-/// Perform full tick of engine, including property computation, lifecycle event handling, and rendering side-effects.
-/// Returns a message queue of native rendering actions encoded as a Flexbuffer via FFI to Swift.
-/// The returned message queue requires explicit deallocation: `pax_deallocate_message_queue`
-#[no_mangle] //Exposed to Swift via paxchassismacos.h
-pub extern "C" fn pax_tick(
- engine_container: *mut PaxEngineContainer,
- cgContext: *mut c_void,
- width: f32,
- height: f32,
-) -> *mut NativeMessageQueue {
- // note that f32 is essentially `CFloat`, per: https://doc.rust-lang.org/std/os/raw/type.c_float.html
- let mut engine = unsafe { Box::from_raw((*engine_container)._engine) };
-
- let will_cast_cgContext = cgContext as *mut CGContext;
- let ctx = unsafe { &mut *will_cast_cgContext };
- let render_context = CoreGraphicsContext::new_y_up(ctx, height as f64, None);
- (*engine).set_viewport_size((width as f64, height as f64));
-
- let mut render_contexts = HashMap::new();
- render_contexts.insert(format!("{}", 0), render_context);
-
- let messages = (*engine).tick(&mut render_contexts);
-
- let wrapped_queue = MessageQueue { messages };
- let mut serializer = flexbuffers::FlexbufferSerializer::new();
-
- //side-effectfully serialize, mutating `serializer`
- wrapped_queue.serialize(&mut serializer).unwrap();
-
- let data_buffer = serializer.take_buffer();
- let length = data_buffer.len();
-
- let leaked_data: ManuallyDrop> = ManuallyDrop::new(data_buffer.into_boxed_slice());
-
- let queue_container = unsafe {
- transmute(Box::new(NativeMessageQueue {
- data_ptr: Box::into_raw(ManuallyDrop::into_inner(leaked_data)),
- length: length as u64,
- }))
- };
-
- //`Box::into_raw` is our necessary manual clean-up, acting as a trigger to drop all of the RefCell::borrow_mut's throughout the tick lifecycle
- unsafe { (*engine_container)._engine = Box::into_raw(engine) };
-
- queue_container
-}
-
-/// Required manual cleanup callback from Swift after reading a frame's message queue.
-/// If this is not called after `pax_tick` is invoked, we will have a memory leak.
-#[no_mangle] //Exposed to Swift via paxchassismacos.h
-pub extern "C" fn pax_dealloc_message_queue(queue: *mut NativeMessageQueue) {
- unsafe {
- let queue_container = Box::from_raw(queue);
- let data_buffer = Box::from_raw(queue_container.data_ptr);
- drop(data_buffer);
- drop(queue_container);
- }
-}
+pub use pax_chassis_common::core_graphics_c_bridge::*;
\ No newline at end of file
diff --git a/pax-cli/src/main.rs b/pax-cli/src/main.rs
index 49b8e56af..f6e2b7d5d 100644
--- a/pax-cli/src/main.rs
+++ b/pax-cli/src/main.rs
@@ -1,10 +1,9 @@
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
use colored::{ColoredString, Colorize};
use std::io::Write;
-use std::path::Path;
use std::sync::{Arc, Mutex};
use std::time::Duration;
-use std::{fs, process, thread};
+use std::{process, thread};
use pax_compiler::{CreateContext, RunContext, RunTarget};
extern crate pax_language_server;
@@ -14,7 +13,9 @@ mod http;
use signal_hook::consts::{SIGINT, SIGTERM};
use signal_hook::iterator::Signals;
+/// `pax-cli` entrypoint
fn main() -> Result<(), ()> {
+
//Shared state to store child processes keyed by static unique string IDs, for cleanup tracking
let process_child_ids: Arc>> = Arc::new(Mutex::new(vec![]));
// Shared state to store the new version info if available.
@@ -26,20 +27,6 @@ fn main() -> Result<(), ()> {
http::check_for_update(cloned_new_version_info);
});
- // Create a separate thread to handle signals e.g. via CTRL+C
- let mut signals = Signals::new(&[SIGINT, SIGTERM]).unwrap();
- let cloned_version_info = Arc::clone(&new_version_info);
- let cloned_process_child_ids = Arc::clone(&process_child_ids);
- thread::spawn(move || {
- for _sig in signals.forever() {
- println!("\nInterrupt received. Cleaning up child processes...");
- perform_cleanup(
- Arc::clone(&cloned_version_info),
- Arc::clone(&cloned_process_child_ids),
- );
- }
- });
-
#[allow(non_snake_case)]
let ARG_PATH = Arg::with_name("path")
.short("p")
@@ -53,17 +40,21 @@ fn main() -> Result<(), ()> {
.long("verbose")
.takes_value(false);
+ const DEFAULT_TARGET : &str = "web";
#[allow(non_snake_case)]
let ARG_TARGET = Arg::with_name("target")
.short("t")
.long("target")
- //Default to web -- perhaps the ideal would be to discover host
- //platform and run appropriate native harness. Web is a suitable,
- //sane default for now.
- .default_value("web")
+ .default_value(DEFAULT_TARGET)
.help("Specify the target platform on which to run. Will run in platform-specific demo harness.")
.takes_value(true);
+ #[allow(non_snake_case)]
+ let ARG_RELEASE = Arg::with_name("release")
+ .long("release")
+ .takes_value(false)
+ .help("Build in Release mode, with appropriate platform-specific optimizations.");
+
#[allow(non_snake_case)]
let ARG_LIBDEV = Arg::with_name("libdev")
.long("libdev")
@@ -78,7 +69,7 @@ fn main() -> Result<(), ()> {
let matches = App::new("pax")
.name("pax")
- .bin_name("pax")
+ .bin_name("pax-cli")
.about("Pax CLI including compiler and dev tooling")
.version(crate_version!())
.setting(AppSettings::SubcommandRequiredElseHelp)
@@ -98,6 +89,7 @@ fn main() -> Result<(), ()> {
.arg( ARG_TARGET.clone() )
.arg( ARG_VERBOSE.clone() )
.arg( ARG_LIBDEV.clone() )
+ .arg( ARG_RELEASE.clone() )
)
.subcommand(
App::new("clean")
@@ -107,6 +99,7 @@ fn main() -> Result<(), ()> {
)
.subcommand(
App::new("create")
+ .about("Creates a new Pax + Rust project at the specified path, including necessary boilerplate and default configuration.")
.alias("new")
.arg(Arg::with_name("path")
.help("File system path where the new project should be created. If not provided with --path, it should directly follow 'create'")
@@ -116,12 +109,6 @@ fn main() -> Result<(), ()> {
)
.subcommand(
App::new("libdev")
- .subcommand(
- App::new("build-chassis")
- .arg( ARG_PATH.clone() )
- .arg( ARG_TARGET.clone() )
- .about("Runs cargo build on the codegenned chassis, within the .pax folder contained within the specified `path`. Useful for core development, e.g. building compiler features or compiler debugging. Expected to fail if the whole compiler has not run at least once.")
- )
.subcommand(
App::new("parse")
.arg( ARG_PATH.clone() )
@@ -132,10 +119,29 @@ fn main() -> Result<(), ()> {
.subcommand(ARG_LSP.clone())
.get_matches();
- let _ = perform_nominal_action(matches, Arc::clone(&process_child_ids));
- perform_cleanup(new_version_info, process_child_ids);
+ // Clap doesn't easily let us check a "global" arg without performing individual `match`es.
+ // Since we want to know at this top level whether `--libdev` is present, we will parse it manually.
+ let args: Vec = std::env::args().collect();
+ let is_libdev_mode = args.contains(&"--libdev".to_string());
+
+ // Create a separate thread to handle signals e.g. via CTRL+C
+ let mut signals = Signals::new(&[SIGINT, SIGTERM]).unwrap();
+ let cloned_version_info = Arc::clone(&new_version_info);
+ let cloned_process_child_ids = Arc::clone(&process_child_ids);
+ thread::spawn(move || {
+ for _sig in signals.forever() {
+ println!("\nInterrupt received. Cleaning up child processes...");
+ perform_cleanup(
+ Arc::clone(&cloned_version_info),
+ Arc::clone(&cloned_process_child_ids),
+ is_libdev_mode,
+ );
+ }
+ });
- Ok(())
+ let res = perform_nominal_action(matches, Arc::clone(&process_child_ids));
+ perform_cleanup(new_version_info, process_child_ids, is_libdev_mode);
+ res
}
fn perform_nominal_action(
@@ -156,6 +162,7 @@ fn perform_nominal_action(
should_also_run: true,
is_libdev_mode,
process_child_ids,
+ is_release: false,
})
}
("build", Some(args)) => {
@@ -163,6 +170,7 @@ fn perform_nominal_action(
let path = args.value_of("path").unwrap().to_string(); //default value "."
let verbose = args.is_present("verbose");
let is_libdev_mode = args.is_present("libdev");
+ let is_release = args.is_present("release");
pax_compiler::perform_build(&RunContext {
target: RunTarget::from(target.as_str()),
@@ -171,6 +179,7 @@ fn perform_nominal_action(
verbose,
is_libdev_mode,
process_child_ids,
+ is_release,
})
}
("clean", Some(args)) => {
@@ -211,38 +220,6 @@ fn perform_nominal_action(
Ok(())
}
- ("build-chassis", Some(args)) => {
- let target = args.value_of("target").unwrap().to_lowercase();
- let path = args.value_of("path").unwrap().to_string(); //default value "."
-
- let working_path = Path::new(&path).join(".pax");
- let pax_dir = fs::canonicalize(working_path).unwrap();
-
- let ctx = RunContext {
- target: RunTarget::from(target.as_str()),
- path,
- verbose: true,
- should_also_run: false,
- is_libdev_mode: true,
- process_child_ids: Arc::new(Mutex::new(vec![])),
- };
-
- let output = pax_compiler::build_chassis_with_cartridge(
- &pax_dir,
- &ctx,
- process_child_ids,
- );
-
- // Forward both stdout and stderr
- std::io::stderr()
- .write_all(output.stderr.as_slice())
- .unwrap();
- std::io::stdout()
- .write_all(output.stdout.as_slice())
- .unwrap();
-
- Ok(())
- }
_ => {
unreachable!()
}
@@ -259,6 +236,7 @@ fn perform_nominal_action(
fn perform_cleanup(
new_version_info: Arc>>,
process_child_ids: Arc>>,
+ is_libdev_mode: bool,
) {
//1. kill any running child processes
if let Ok(process_child_ids_lock) = process_child_ids.lock() {
@@ -270,64 +248,66 @@ fn perform_cleanup(
//2. print update message if appropriate
if let Ok(new_version_lock) = new_version_info.lock() {
- if let Some(new_version) = new_version_lock.as_ref() {
- if new_version != "" {
- //Print our banner if we have a concrete value stored in the new version mutex
- const TOTAL_LENGTH: usize = 60;
- let stars_line: ColoredString =
- "*".repeat(TOTAL_LENGTH).bright_white().on_bright_black();
- let empty_line: ColoredString =
- " ".repeat(TOTAL_LENGTH).bright_white().on_bright_black();
-
- let new_version_static = " A new version of the Pax CLI is available: ";
- let new_version_formatted = format!("{}{}", new_version_static, new_version);
- let new_version_line: ColoredString =
- format!("{: (
type_id: "isize".to_string(),
};
- let scope = HashMap::from([
+ let scope: HashMap = HashMap::from([
//`elem` property (by specified name)
(elem_id.clone(), property_definition),
]);
diff --git a/pax-compiler/src/lib.rs b/pax-compiler/src/lib.rs
index c42770963..f24f09123 100644
--- a/pax-compiler/src/lib.rs
+++ b/pax-compiler/src/lib.rs
@@ -1,21 +1,12 @@
extern crate core;
-use lazy_static::lazy_static;
-
-use include_dir::{include_dir, Dir};
-
pub mod expressions;
pub mod manifest;
pub mod parsing;
pub mod templating;
-use pax_runtime_api::CommonProperties;
-
use manifest::PaxManifest;
-use rust_format::Formatter;
-
-use fs_extra::dir::{self, CopyOptions};
-use itertools::Itertools;
+use pax_runtime_api::CommonProperties;
use std::borrow::Borrow;
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
@@ -23,37 +14,77 @@ use std::fs;
use std::io::Write;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
+use std::thread;
use actix_web::middleware::Logger;
use actix_web::{App, HttpServer};
use env_logger;
use flate2::read::GzDecoder;
+use fs_extra::dir::{self, CopyOptions};
+use itertools::Itertools;
+use rust_format::Formatter;
use std::net::TcpListener;
use tar::Archive;
+use include_dir::{include_dir, Dir};
+use lazy_static::lazy_static;
+
#[cfg(unix)]
-use std::os::unix::process::CommandExt; // For the .pre_exec() method
+use std::os::unix::process::CommandExt;
use crate::manifest::{
ComponentDefinition, EventDefinition, ExpressionSpec, LiteralBlockDefinition,
TemplateNodeDefinition, TypeDefinition, TypeTable, ValueDefinition,
};
+
use crate::templating::{
press_template_codegen_cartridge_component_factory,
press_template_codegen_cartridge_render_node_literal,
TemplateArgsCodegenCartridgeComponentFactory, TemplateArgsCodegenCartridgeRenderNodeLiteral,
};
+
use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use toml_edit::Item;
-//relative to pax_dir
-pub const REEXPORTS_PARTIAL_RS_PATH: &str = "reexports.partial.rs";
+lazy_static! {
+ #[allow(non_snake_case)]
+ static ref PAX_BADGE: ColoredString = "[Pax]".bold().on_black().white();
+
+ static ref DIR_IGNORE_LIST_MACOS : Vec<&'static str> = vec!["target", ".build", ".git"];
+ static ref DIR_IGNORE_LIST_WEB : Vec<&'static str> = vec![".git"];
+}
+
+static PAX_CREATE_TEMPLATE: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/new-project-template");
+
+const PAX_CREATE_TEMPLATE_DIR_NAME: &str = "new-project-template";
+const PKG_DIR_NAME: &str = "pkg";
+const BUILD_DIR_NAME: &str = "build";
+const PUBLIC_DIR_NAME: &str = "public";
+const ASSETS_DIR_NAME: &str = "assets";
+const REEXPORTS_PARTIAL_FILE_NAME: &str = "reexports.partial.rs";
+const RUST_IOS_DYLIB_FILE_NAME: &str = "libpaxchassisios.dylib";
+const RUST_MACOS_DYLIB_FILE_NAME: &str = "libpaxchassismacos.dylib";
+const PORTABLE_DYLIB_INSTALL_NAME: &str = "@rpath/PaxCartridge.framework/PaxCartridge";
+
+const XCODE_MACOS_TARGET_DEBUG: &str = "Pax macOS (Development)";
+const XCODE_MACOS_TARGET_RELEASE: &str = "Pax macOS (Release)";
+const XCODE_IOS_TARGET_DEBUG: &str = "Pax iOS (Development)";
+const XCODE_IOS_TARGET_RELEASE: &str = "Pax iOS (Release)";
+
+// These package IDs represent the directory / package names inside the xcframework,
+const MACOS_MULTIARCH_PACKAGE_ID: &str = "macos-arm64_x86_64";
+const IOS_SIMULATOR_MULTIARCH_PACKAGE_ID: &str = "ios-arm64_x86_64-simulator";
+const IOS_PACKAGE_ID: &str = "ios-arm64";
+
+const ERR_SPAWN: &str = "failed to spawn child";
//whitelist of package ids that are relevant to the compiler, e.g. for cloning & patching, for assembling FS paths,
//or for looking up package IDs from a userland Cargo.lock.
-const ALL_PKGS: [&'static str; 12] = [
+const ALL_PKGS: [&'static str; 14] = [
"pax-cartridge",
+ "pax-chassis-common",
+ "pax-chassis-ios",
"pax-chassis-macos",
"pax-chassis-web",
"pax-cli",
@@ -67,73 +98,23 @@ const ALL_PKGS: [&'static str; 12] = [
"pax-std",
];
-/// Returns a sorted and de-duped list of combined_reexports.
-fn generate_reexports_partial_rs(pax_dir: &PathBuf, manifest: &PaxManifest) {
- let imports = manifest.import_paths.clone().into_iter().sorted().collect();
-
- let file_contents = &bundle_reexports_into_namespace_string(&imports);
-
- let path = pax_dir.join(Path::new(REEXPORTS_PARTIAL_RS_PATH));
- fs::write(path, file_contents).unwrap();
-}
-
-fn bundle_reexports_into_namespace_string(sorted_reexports: &Vec) -> String {
- let mut root = NamespaceTrieNode {
- node_string: None,
- children: Default::default(),
- };
-
- for s in sorted_reexports {
- root.insert(s);
- }
-
- root.serialize_to_reexports()
-}
-
-fn update_property_prefixes_in_place(manifest: &mut PaxManifest, host_crate_info: &HostCrateInfo) {
- let mut updated_type_table = HashMap::new();
- manifest.type_table.iter_mut().for_each(|t| {
- t.1.type_id_escaped = t.1.type_id_escaped.replace("{PREFIX}", "");
- t.1.type_id =
- t.1.type_id
- .replace("{PREFIX}", &host_crate_info.import_prefix);
- t.1.property_definitions.iter_mut().for_each(|pd| {
- pd.type_id = pd
- .type_id
- .replace("{PREFIX}", &host_crate_info.import_prefix);
- });
- updated_type_table.insert(
- t.0.replace("{PREFIX}", &host_crate_info.import_prefix),
- t.1.clone(),
- );
- });
- std::mem::swap(&mut manifest.type_table, &mut updated_type_table);
-}
-
-// The stable output directory for generated / copied files
-const PAX_DIR_PKG_PATH: &str = "pkg";
-
-fn clone_all_dependencies_to_tmp(
- pax_dir: &PathBuf,
- pax_version: &Option,
- ctx: &RunContext,
-) {
- let dest_pkg_root = pax_dir.join(PAX_DIR_PKG_PATH);
+/// Clone all dependencies to `.pax/pkg`. Similar in spirit to the Cargo package cache,
+/// this temp directory enables Pax to codegen and building in the context of the larger monorepo,
+/// working around various constraints with Cargo (for example, limits surrounding the `patch` directive.)
+///
+/// The packages in `.pax/pkg` are both where we write our codegen (into pax-cartridge and pax-properties-coproduct)
+/// and where we build chassis and chassis-interfaces. (for example, running `wasm-pack` inside `.pax/pkg/pax-chassis-web`.
+fn clone_all_to_pkg_dir(pax_dir: &PathBuf, pax_version: &Option, ctx: &RunContext) {
+ let dest_pkg_root = pax_dir.join(PKG_DIR_NAME);
for pkg in ALL_PKGS {
if ctx.is_libdev_mode {
//Copy all packages from monorepo root on every build. this allows us to propagate changes
//to a libdev build without "sticky caches."
- //
- //Note that this may incur a penalty on libdev build times,
- //since cargo will want to rebuild the whole workspace from scratch on every build. If we want to optimize this,
- //consider a "double buffered" approach, where we copy everything into a fresh new buffer (B), call it `.pax/pkg-tmp`, while leaving (A) `.pax/pkg`
- //unchanged on disk. Bytewise check each file found in B against a prospective match in A, and copy only if different. (B) could also be stored on a virtual
- //FS in memory, to reduce disk churn.
let pax_workspace_root = pax_dir.parent().unwrap().parent().unwrap();
let src = pax_workspace_root.join(pkg);
let dest = dest_pkg_root.join(pkg);
- copy_dir_to(&src, &dest)
+ copy_dir_recursively(&src, &dest, &DIR_IGNORE_LIST_MACOS)
.expect(&format!("Failed to copy from {:?} to {:?}", src, dest));
} else {
let dest = dest_pkg_root.join(pkg);
@@ -190,14 +171,55 @@ fn clone_all_dependencies_to_tmp(
}
}
+/// Returns a sorted and de-duped list of combined_reexports.
+fn generate_reexports_partial_rs(pax_dir: &PathBuf, manifest: &PaxManifest) {
+ let imports = manifest.import_paths.clone().into_iter().sorted().collect();
+
+ let file_contents = &bundle_reexports_into_namespace_string(&imports);
+
+ let path = pax_dir.join(Path::new(REEXPORTS_PARTIAL_FILE_NAME));
+ fs::write(path, file_contents).unwrap();
+}
+
+fn bundle_reexports_into_namespace_string(sorted_reexports: &Vec) -> String {
+ let mut root = NamespaceTrieNode {
+ node_string: None,
+ children: Default::default(),
+ };
+
+ for s in sorted_reexports {
+ root.insert(s);
+ }
+
+ root.serialize_to_reexports()
+}
+
+fn update_property_prefixes_in_place(manifest: &mut PaxManifest, host_crate_info: &HostCrateInfo) {
+ let mut updated_type_table = HashMap::new();
+ manifest.type_table.iter_mut().for_each(|t| {
+ t.1.type_id_escaped = t.1.type_id_escaped.replace("{PREFIX}", "");
+ t.1.type_id =
+ t.1.type_id
+ .replace("{PREFIX}", &host_crate_info.import_prefix);
+ t.1.property_definitions.iter_mut().for_each(|pd| {
+ pd.type_id = pd
+ .type_id
+ .replace("{PREFIX}", &host_crate_info.import_prefix);
+ });
+ updated_type_table.insert(
+ t.0.replace("{PREFIX}", &host_crate_info.import_prefix),
+ t.1.clone(),
+ );
+ });
+ std::mem::swap(&mut manifest.type_table, &mut updated_type_table);
+}
+
fn generate_and_overwrite_properties_coproduct(
pax_dir: &PathBuf,
manifest: &PaxManifest,
host_crate_info: &HostCrateInfo,
) {
- let target_dir = pax_dir
- .join(PAX_DIR_PKG_PATH)
- .join("pax-properties-coproduct");
+ let target_dir = pax_dir.join(PKG_DIR_NAME).join("pax-properties-coproduct");
let target_cargo_full_path = fs::canonicalize(target_dir.join("Cargo.toml")).unwrap();
let mut target_cargo_toml_contents =
@@ -314,7 +336,7 @@ fn generate_and_overwrite_cartridge(
manifest: &PaxManifest,
host_crate_info: &HostCrateInfo,
) {
- let target_dir = pax_dir.join(PAX_DIR_PKG_PATH).join("pax-cartridge");
+ let target_dir = pax_dir.join(PKG_DIR_NAME).join("pax-cartridge");
let target_cargo_full_path = fs::canonicalize(target_dir.join("Cargo.toml")).unwrap();
let mut target_cargo_toml_contents =
@@ -391,38 +413,6 @@ fn generate_and_overwrite_cartridge(
let consts = vec![]; //TODO!
- //Traverse component tree starting at root
- //build a N/PIT in memory for each component (maybe this can be automatically serialized for component factories?)
- // handle each kind of attribute:
- // Literal(String),
- // inline into N/PIT
- // Expression(String),
- // pencil in the ID; handle the expression separately (build ExpressionSpec & friends)
- // Identifier(String),
- // syntactic sugar for an expression with a single dependency, returning that dependency
- // EventBindingTarget(String),
- // ensure this gets added to the HandlerRegistry for this component; rely on ugly error messages for now
- //
- // for serialization to RIL, generate InstantiationArgs for each node, special-casing built-ins like Repeat, Slot
- //
- // Also decide whether to join settings blocks in this work
- //
- // Compile expressions during traversal, keeping track of "compile-time stack" for symbol resolution
- // If `const` is bit off for this work, must first populate symbols via pax_const => PaxManifest
- // -- must also choose scoping rules; probably just component-level scoping for now
- //
- // Throw errors when symbols in expressions cannot be resolved; ensure path forward to developer-friendly error messages
- // For reference, Rust's message is:
- // error[E0425]: cannot find value `not_defined` in this scope
- // --> pax-compiler/src/main.rs:404:13
- // |
- // 404 | let y = not_defined + 6;
- // | ^^^^^^^^^^^ not found in this scope
- // Python uses:
- // NameError: name 'z' is not defined
- // JavaScript uses:
- // Uncaught ReferenceError: not_defined is not defined
-
let mut expression_specs: Vec = manifest
.expression_specs
.as_ref()
@@ -450,8 +440,7 @@ fn generate_and_overwrite_cartridge(
},
);
- // Re: formatting the generated output, see prior art at `_format_generated_lib_rs`
- //write String to file
+ // Re: formatting the generated Rust code, see prior art at `_format_generated_lib_rs`
fs::write(target_dir.join("src/lib.rs"), generated_lib_rs).unwrap();
}
@@ -728,22 +717,18 @@ fn recurse_generate_render_nodes_literal(
Some(format!("PropertyLiteral::new({})", lv))
}
ValueDefinition::Expression(_, id)
- | ValueDefinition::Identifier(_, id) => {
- Some(format!(
- "PropertyExpression::new({})",
- id.expect("Tried to use expression but it wasn't compiled")
- ))
- }
- ValueDefinition::Block(block) => {
- Some(format!(
- "PropertyLiteral::new({})",
- recurse_literal_block(
- block.clone(),
- pd.get_type_definition(&rngc.type_table),
- host_crate_info
- )
- ))
- }
+ | ValueDefinition::Identifier(_, id) => Some(format!(
+ "PropertyExpression::new({})",
+ id.expect("Tried to use expression but it wasn't compiled")
+ )),
+ ValueDefinition::Block(block) => Some(format!(
+ "PropertyLiteral::new({})",
+ recurse_literal_block(
+ block.clone(),
+ pd.get_type_definition(&rngc.type_table),
+ host_crate_info
+ )
+ )),
_ => {
panic!("Incorrect value bound to inline setting")
}
@@ -757,7 +742,6 @@ fn recurse_generate_render_nodes_literal(
}
};
-
if let Some(ril_literal_string) = ril_literal_string {
Some((pd.name.clone(), ril_literal_string))
} else {
@@ -982,7 +966,7 @@ pub fn run_parser_binary(path: &str, process_child_ids: Arc>>) ->
cmd.pre_exec(pre_exec_hook);
}
- let child = cmd.spawn().expect("failed to spawn child");
+ let child = cmd.spawn().expect(ERR_SPAWN);
// child.stdin.take().map(drop);
let output = wait_with_output(&process_child_ids, child);
@@ -994,6 +978,7 @@ use colored::{ColoredString, Colorize};
use crate::parsing::escape_identifier;
use serde::Deserialize;
+use serde_json::Value;
#[derive(Debug, Deserialize)]
struct Metadata {
@@ -1043,11 +1028,6 @@ fn get_version_of_whitelisted_packages(path: &str) -> Result Result<(), ()> {
} else {
Some(get_version_of_whitelisted_packages(&ctx.path).unwrap())
};
- clone_all_dependencies_to_tmp(&pax_dir, &pax_version, &ctx);
+ clone_all_to_pkg_dir(&pax_dir, &pax_version, &ctx);
println!("{} 🛠️ Building parser binary with `cargo`...", *PAX_BADGE);
// Run parser bin from host project with `--features parser`
@@ -1075,11 +1055,11 @@ pub fn perform_build(ctx: &RunContext) -> Result<(), ()> {
std::io::stderr()
.write_all(output.stderr.as_slice())
.unwrap();
- assert_eq!(
- output.status.code().unwrap(),
- 0,
- "Parsing failed — there is likely a syntax error in the provided pax"
- );
+
+ if !output.status.success() {
+ println!("Parsing failed — there is likely a syntax error in the provided pax");
+ return Err(());
+ }
let out = String::from_utf8(output.stdout).unwrap();
let mut manifest: PaxManifest =
@@ -1098,44 +1078,9 @@ pub fn perform_build(ctx: &RunContext) -> Result<(), ()> {
//7. Build the appropriate `chassis` from source, with the patched `Cargo.toml`, Properties Coproduct, and Cartridge from above
println!("{} 🧱 Building cartridge with `cargo`", *PAX_BADGE);
- build_chassis_with_cartridge(&pax_dir, &ctx, Arc::clone(&ctx.process_child_ids));
-
- if ctx.should_also_run {
- //8a::run: compile and run `interface`, with freshly built chassis plugged in
- println!(
- "{} 🐇 Running Pax {}...",
- *PAX_BADGE,
- <&RunTarget as Into<&str>>::into(&ctx.target)
- );
- } else {
- //8b::compile: compile and write executable binary / package to disk at specified or implicit path
- println!(
- "{} 🛠 Compiling executable package for {}...",
- *PAX_BADGE,
- <&RunTarget as Into<&str>>::into(&ctx.target)
- );
- }
- build_interface_with_chassis(&pax_dir, &ctx, Arc::clone(&ctx.process_child_ids));
-
- Ok(())
-}
-
-fn copy_dir_to(src_dir: &Path, dst_dir: &Path) -> std::io::Result<()> {
- if !dst_dir.exists() {
- fs::create_dir_all(dst_dir)?;
- }
-
- for entry_result in fs::read_dir(src_dir)? {
- let entry = entry_result?;
- let file_type = entry.file_type()?;
- let src_path = entry.path();
- let dst_path = dst_dir.join(entry.file_name());
-
- if file_type.is_dir() {
- copy_dir_to(&src_path, &dst_path)?;
- } else {
- fs::copy(&src_path, &dst_path)?;
- }
+ let res = build_chassis_with_cartridge(&pax_dir, &ctx, Arc::clone(&ctx.process_child_ids));
+ if let Err(()) = res {
+ return Err(());
}
Ok(())
@@ -1183,95 +1128,27 @@ fn start_static_http_server(fs_path: PathBuf) -> std::io::Result<()> {
runtime
}
-fn build_interface_with_chassis(
- pax_dir: &PathBuf,
- ctx: &RunContext,
- process_child_ids: Arc>>,
-) {
- let target_str: &str = ctx.target.borrow().into();
- let target_str_lower: &str = &target_str.to_lowercase();
-
- let interface_path = pax_dir
- .join(PAX_DIR_PKG_PATH)
- .join(format!("pax-chassis-{}", target_str_lower))
- .join(match ctx.target {
- RunTarget::Web => "interface",
- RunTarget::MacOS => "pax-dev-harness-macos",
- });
-
- let is_web = if let RunTarget::Web = ctx.target {
- true
- } else {
- false
- };
-
- let target_folder: &str = ctx.target.borrow().into();
-
- let output_path = pax_dir.join("build").join(target_folder);
- let output_path_str = output_path.to_str().unwrap();
-
- std::fs::create_dir_all(&output_path).ok();
-
- let verbose_val = format!("{}", ctx.verbose);
- let exclude_arch_val = if std::env::consts::ARCH == "aarch64" {
- "x86_64"
- } else {
- "arm64"
- };
- if is_web {
- let asset_src = pax_dir.join("..").join("assets");
- let asset_dest = interface_path.join("public").join("assets");
-
- // Create target assets directory
- if let Err(e) = fs::create_dir_all(&asset_dest) {
- eprintln!("Error creating directory {:?}: {}", asset_dest, e);
- }
- // Perform recursive copy from userland `assets/` to built `assets/`
- if let Err(e) = copy_dir_recursively(&asset_src, &asset_dest) {
- eprintln!("Error copying assets: {}", e);
- }
-
- // Start local server if this is a `run` rather than a `build`
- if ctx.should_also_run {
- let _ = start_static_http_server(interface_path.join("public"));
- }
- } else {
- let script = "./run-debuggable-mac-app.sh";
- let should_also_run = &format!("{}", ctx.should_also_run);
- let mut cmd = Command::new(script);
- cmd.current_dir(&interface_path)
- .arg(verbose_val)
- .arg(exclude_arch_val)
- .arg(should_also_run)
- .arg(output_path_str)
- .stdout(std::process::Stdio::inherit())
- .stderr(if ctx.verbose {
- std::process::Stdio::inherit()
- } else {
- std::process::Stdio::piped()
- });
-
- #[cfg(unix)]
- unsafe {
- cmd.pre_exec(pre_exec_hook);
+/// Helper recursive fs copy method, like fs::copy, but suited for our purposes.
+/// Includes ability to ignore directories by name during recursion.
+fn copy_dir_recursively(
+ src: &Path,
+ dest: &Path,
+ ignore_list: &[&str],
+) -> Result<(), Box> {
+ if src.is_dir() {
+ // If the directory name is in the ignore list, we skip this directory
+ if ignore_list.contains(&src.file_name().unwrap().to_str().unwrap()) {
+ return Ok(());
}
- let child = cmd.spawn().expect("failed to spawn child");
- // child.stdin.take().map(drop);
- let _output = wait_with_output(&process_child_ids, child);
- }
-}
-
-fn copy_dir_recursively(src: &Path, dest: &Path) -> Result<(), Box> {
- if src.is_dir() {
- // If source is a directory, create the corresponding directory in the destination,
+ // Create the corresponding directory in the destination,
// and copy its contents recursively
fs::create_dir_all(dest)?;
for entry in fs::read_dir(src)? {
let entry = entry?;
let path = entry.path();
let dest_child = dest.join(path.file_name().ok_or("Invalid file name")?);
- copy_dir_recursively(&path, &dest_child)?;
+ copy_dir_recursively(&path, &dest_child, ignore_list)?;
}
} else {
// If source is a file, just copy it to the destination
@@ -1280,11 +1157,11 @@ fn copy_dir_recursively(src: &Path, dest: &Path) -> Result<(), Box>>,
-) -> Output {
+) -> Result<(), ()> {
let target: &RunTarget = &ctx.target;
let target_str: &str = target.into();
let target_str_lower = &target_str.to_lowercase();
let pax_dir = PathBuf::from(pax_dir.to_str().unwrap());
let chassis_path = pax_dir
- .join(PAX_DIR_PKG_PATH)
+ .join(PKG_DIR_NAME)
.join(format!("pax-chassis-{}", target_str_lower));
+ let is_release: bool = ctx.is_release;
+ let is_ios = if let RunTarget::iOS = target {
+ true
+ } else {
+ false
+ };
+
+ let build_mode_name: &str = if is_release { "release" } else { "debug" };
+
+ let interface_path = pax_dir
+ .join(PKG_DIR_NAME)
+ .join(format!("pax-chassis-{}", target_str_lower))
+ .join("interface");
+
//Inject `patch` directive, which allows userland projects to refer to concrete versions like `0.4.0`, while we
//swap them for our locally cloned filesystem versions during compilation.
let existing_cargo_toml_path = chassis_path.join("Cargo.toml");
@@ -1331,26 +1222,722 @@ pub fn build_chassis_with_cartridge(
//string together a shell call to build our chassis, with cartridge inserted via `patch`
match target {
- RunTarget::MacOS => {
- let mut cmd = Command::new("cargo");
- cmd.current_dir(&chassis_path)
- .arg("build")
- .arg("--color")
- .arg("always")
- .env("PAX_DIR", &pax_dir)
+ RunTarget::macOS | RunTarget::iOS => {
+ //0: Rust arch string, for passing to cargo
+ //1: Apple arch string, for addressing xcframework
+ let target_mappings: &[(&str, &str)] = if let RunTarget::macOS = target {
+ if is_release {
+ &[
+ ("aarch64-apple-darwin", "macos-arm64"),
+ ("x86_64-apple-darwin", "macos-x86_64"),
+ ]
+ } else {
+ // Build only relevant archs for dev
+ if std::env::consts::ARCH == "x86_64" {
+ &[("x86_64-apple-darwin", "macos-x86_64")]
+ } else {
+ &[("aarch64-apple-darwin", "macos-arm64")]
+ }
+ }
+ } else {
+ // Build all archs for iOS builds. We could limit these like we do for macOS
+ // dev builds, but at time of intial authoring, it was slowing zb down.
+ &[
+ ("aarch64-apple-ios", "ios-arm64"),
+ ("x86_64-apple-ios", "iossimulator-x86_64"),
+ ("aarch64-apple-ios-sim", "iossimulator-arm64"),
+ ]
+ };
+
+ let dylib_file_name = if let RunTarget::macOS = target {
+ RUST_MACOS_DYLIB_FILE_NAME
+ } else {
+ RUST_IOS_DYLIB_FILE_NAME
+ };
+
+ let mut handles = Vec::new();
+
+ //(arch id, single-platform .dylib path, stdout/stderr from build)
+ let build_results: Arc>> =
+ Arc::new(Mutex::new(HashMap::new()));
+
+ let targets_single_string = target_mappings
+ .iter()
+ .map(|tm| tm.1.to_string())
+ .collect::>()
+ .join(", ")
+ .bold();
+ println!(
+ "{} 🧶 Compiling targets {{{}}} in {} mode using {} threads...\n",
+ *PAX_BADGE,
+ &targets_single_string,
+ &build_mode_name.to_string().bold(),
+ target_mappings.len()
+ );
+
+ let mut index = 0;
+ for target_mapping in target_mappings {
+ let chassis_path = chassis_path.clone();
+ let pax_dir = pax_dir.clone();
+
+ let process_child_ids_threadsafe = process_child_ids.clone();
+ let build_results_threadsafe = build_results.clone();
+
+ let handle = thread::spawn(move || {
+ let mut cmd = Command::new("cargo");
+ cmd.current_dir(&chassis_path)
+ .arg("build")
+ .arg("--color")
+ .arg("always")
+ .arg("--target")
+ .arg(target_mapping.0)
+ .env("PAX_DIR", &pax_dir)
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped());
+
+ if is_release {
+ cmd.arg("--release");
+ }
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+
+ let child = cmd.spawn().expect(ERR_SPAWN);
+
+ //Execute `cargo build`, which generates our dylibs
+ let output = wait_with_output(&process_child_ids_threadsafe, child);
+
+ let dylib_src = chassis_path
+ .join("target")
+ .join(target_mapping.0)
+ .join(build_mode_name)
+ .join(dylib_file_name);
+
+ let new_val = (
+ target_mapping.1.to_string(),
+ dylib_src.to_str().unwrap().to_string(),
+ output,
+ );
+ build_results_threadsafe
+ .lock()
+ .unwrap()
+ .insert(index, new_val);
+ });
+ index = index + 1;
+ handles.push(handle);
+ }
+
+ let mut index = 0;
+ // Wait for all threads to complete and print their outputs
+ for handle in handles {
+ handle.join().unwrap();
+ }
+
+ let results = build_results.lock().unwrap();
+
+ let mut should_abort = false;
+ //Print stdout/stderr
+ for i in 0..target_mappings.len() {
+ let result = results.get(&(i as u32)).unwrap();
+ let target = &result.0;
+ let output = &result.2;
+
+ let stdout = String::from_utf8_lossy(&output.stdout).to_string();
+ let stderr = String::from_utf8_lossy(&output.stderr).to_string();
+
+ if stdout != "" || stderr != "" {
+ println!("{} build finished with output:", &target);
+ }
+ if stdout != "" {
+ println!("{}", &stdout);
+ }
+ if stderr != "" {
+ eprintln!("{}", &stderr);
+ }
+
+ if !output.status.success() {
+ should_abort = true;
+ }
+
+ index = index + 1;
+ }
+
+ if should_abort {
+ eprintln!("Failed to build one or more targets with Cargo. Aborting.");
+ return Err(());
+ }
+
+ // Update the `install name` of each Rust-built .dylib, instead of the default-output absolute file paths
+ // embedded in each .dylib. This allows our .dylibs to be portably embedded into an SPM module.
+ let result = results.iter().try_for_each(|res| {
+ let dylib_path = &res.1.1;
+ let mut cmd = Command::new("install_name_tool");
+ cmd
+ .arg("-id")
+ .arg(PORTABLE_DYLIB_INSTALL_NAME)
+ .arg(dylib_path);
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+ let child = cmd.spawn().unwrap();
+ let output = wait_with_output(&process_child_ids, child);
+ if !output.status.success() {
+ println!("Failed to rewrite dynamic library install name with install_name_tool. Aborting.");
+ return Err(());
+ }
+
+ Ok(())
+ });
+
+ match result {
+ Err(_) => {
+ return Err(());
+ }
+ _ => {}
+ };
+
+ let macos_dylib_dest = pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-common")
+ .join("pax-swift-cartridge")
+ .join("PaxCartridge.xcframework")
+ .join(MACOS_MULTIARCH_PACKAGE_ID)
+ .join("PaxCartridge.framework")
+ .join("PaxCartridge");
+
+ let simulator_dylib_dest = pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-common")
+ .join("pax-swift-cartridge")
+ .join("PaxCartridge.xcframework")
+ .join(IOS_SIMULATOR_MULTIARCH_PACKAGE_ID)
+ .join("PaxCartridge.framework")
+ .join("PaxCartridge");
+
+ let iphone_native_dylib_dest = pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-common")
+ .join("pax-swift-cartridge")
+ .join("PaxCartridge.xcframework")
+ .join(IOS_PACKAGE_ID)
+ .join("PaxCartridge.framework")
+ .join("PaxCartridge");
+
+ if is_release || is_ios {
+ // Merge architecture-specific binaries with `lipo` (this is an undocumented requirement
+ // of multi-arch builds + xcframeworks for the Apple toolchain; we cannot bundle two
+ // macos arch .frameworks in an xcframework; they must lipo'd into a single .framework + dylib.
+ // Similarly, iOS binaries require a particular bundling for simulator & device builds.)
+ println!(
+ "{} 🖇️ Combining architecture-specific binaries with `lipo`...",
+ *PAX_BADGE
+ );
+
+ if let RunTarget::macOS = target {
+ // For macOS, we want to lipo both our arm64 and x86_64 dylibs into a single binary,
+ // then bundle that single binary into a single framework within the xcframework.
+
+ let lipo_input_paths = results
+ .iter()
+ .map(|res| res.1 .1.clone())
+ .collect::>();
+
+ // Construct the lipo command
+ let mut lipo_command = Command::new("lipo");
+ lipo_command
+ .arg("-create")
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped());
+
+ // Add each input path to the command
+ for path in &lipo_input_paths {
+ lipo_command.arg(path);
+ }
+
+ // Specify the output path
+ lipo_command.arg("-output").arg(macos_dylib_dest);
+
+ #[cfg(unix)]
+ unsafe {
+ lipo_command.pre_exec(pre_exec_hook);
+ }
+ let child = lipo_command.spawn().expect(ERR_SPAWN);
+ let output = wait_with_output(&process_child_ids, child);
+
+ if !output.status.success() {
+ println!("Failed to combine packages with lipo. Aborting.");
+ return Err(());
+ }
+ } else {
+ // For iOS, we want to:
+ // 1. lipo together both simulator build architectures
+ // 2. copy (a) the lipo'd simulator binary, and (b) the vanilla arm64 iOS binary into the framework
+ let simulator_builds = results
+ .iter()
+ .filter(|res| res.1 .0.starts_with("iossimulator-"))
+ .collect::>();
+ let device_build = results
+ .iter()
+ .filter(|res| res.1 .0.starts_with("ios-"))
+ .collect::>();
+
+ let lipo_input_paths = simulator_builds
+ .iter()
+ .map(|res| res.1 .1.clone())
+ .collect::>();
+
+ // Construct the lipo command
+ let mut lipo_command = Command::new("lipo");
+ lipo_command
+ .arg("-create")
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped());
+
+ // Add each input path to the command
+ for path in &lipo_input_paths {
+ lipo_command.arg(path);
+ }
+
+ // Specify the output path
+ lipo_command.arg("-output").arg(simulator_dylib_dest);
+
+ #[cfg(unix)]
+ unsafe {
+ lipo_command.pre_exec(pre_exec_hook);
+ }
+ let child = lipo_command.spawn().expect(ERR_SPAWN);
+ let output = wait_with_output(&process_child_ids, child);
+ if !output.status.success() {
+ eprintln!("Failed to combine dylibs with lipo. Aborting.");
+ return Err(());
+ }
+
+ //Copy singular device build (iOS, not simulator)
+ let device_dylib_src = &device_build[0].1 .1;
+
+ let _ = fs::copy(device_dylib_src, iphone_native_dylib_dest);
+ }
+ } else {
+ // For macos development builds, instead of lipoing, just drop the singular build into the appropriate output destination
+ // This measure speeds up development builds substantially.
+ // Note that we could do something similar for iOS, but it wasn't immediately in reach at time of authoring (build failed when
+ // providing non-lipo'd binaries in the framework for iOS)
+ let result = results.iter().next().unwrap();
+ let src = &result.1 .1;
+ let dest = macos_dylib_dest;
+ let _ = fs::copy(src, dest);
+ }
+
+ if is_release && is_ios {
+ unimplemented!("\n\n\
+Release builds for Pax iOS are not yet supported because configuration has not been exposed for development teams or code-signing.\n
+You can build a release build manually by configuring the generated xcodeproject in `.pax/pkg/pax-chassis-ios/interface` with your development team and codesigning configuration.\n
+The relevant Framework binaries have been built in release mode at `.pax/pkg/pax-chassis-common/pax-swift-cartridge/` and should be loaded via the above xcodeproject.\n
+You can also use the SPM package exposed at `.pax/pkg/pax-chassis-common/pax-swift-cartridge/` for manual inclusion in your own SwiftUI app.\n
+Note that the temporary directories mentioned above are subject to overwriting.\n\n")
+ }
+
+ let (xcodeproj_path, scheme) = if let RunTarget::macOS = target {
+ (
+ pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-macos")
+ .join("interface")
+ .join("pax-app-macos")
+ .join("pax-app-macos.xcodeproj"),
+ if is_release {
+ XCODE_MACOS_TARGET_RELEASE
+ } else {
+ XCODE_MACOS_TARGET_DEBUG
+ },
+ )
+ } else {
+ (
+ pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-ios")
+ .join("interface")
+ .join("pax-app-ios")
+ .join("pax-app-ios.xcodeproj"),
+ if is_release {
+ XCODE_IOS_TARGET_RELEASE
+ } else {
+ XCODE_IOS_TARGET_DEBUG
+ },
+ )
+ };
+
+ let configuration = if is_release { "Release" } else { "Debug" };
+
+ let build_dest_base = pax_dir
+ .join(BUILD_DIR_NAME)
+ .join(build_mode_name)
+ .join(target_str_lower);
+ let executable_output_dir_path = build_dest_base.join("app");
+ let executable_dot_app_path =
+ executable_output_dir_path.join(&format!("{}.app", &scheme));
+ let _ = fs::create_dir_all(&executable_output_dir_path);
+
+ let sdk = if let RunTarget::iOS = target {
+ if is_release {
+ "iphoneos"
+ } else {
+ "iphonesimulator"
+ }
+ } else {
+ "macosx"
+ };
+
+ println!("{} 💻 Building xcodeproject...", *PAX_BADGE);
+ let mut cmd = Command::new("xcodebuild");
+ cmd.arg("-configuration")
+ .arg(configuration)
+ .arg("-project")
+ .arg(&xcodeproj_path)
+ .arg("-scheme")
+ .arg(scheme)
+ .arg("-sdk")
+ .arg(sdk)
+ .arg(&format!(
+ "CONFIGURATION_BUILD_DIR={}",
+ executable_output_dir_path.to_str().unwrap()
+ ))
.stdout(std::process::Stdio::inherit())
- .stderr(std::process::Stdio::inherit());
+ .stderr(std::process::Stdio::piped());
+
+ if !is_release {
+ cmd.arg("CODE_SIGNING_REQUIRED=NO")
+ .arg("CODE_SIGN_IDENTITY=");
+ }
+
+ if !ctx.verbose {
+ cmd.arg("-quiet");
+ cmd.arg("GCC_WARN_INHIBIT_ALL_WARNINGS=YES");
+ }
#[cfg(unix)]
unsafe {
cmd.pre_exec(pre_exec_hook);
}
-
- let child = cmd.spawn().expect("failed to spawn child");
- // child.stdin.take().map(drop);
+ let child = cmd.spawn().expect(ERR_SPAWN);
let output = wait_with_output(&process_child_ids, child);
- output
+ // Crudely prune out noisy xcodebuild warnings due to an apparent xcode-internal bug at time of authoring, spitting out:
+ // Details: createItemModels creation requirements should not create capability item model for a capability item model that already exists.
+ // Function: createItemModels(for:itemModelSource:)
+ // Thread: <_NSMainThread: 0x600000be02c0>{number = 1, name = main}
+ // Please file a bug at https://feedbackassistant.apple.com with this warning message and any useful information you can provide.
+ // If we get to a point where xcodebuild isn't spitting these errors, we can drop this block of code and just `.inherit` stderr in
+ // the command above.
+ let stderr = String::from_utf8_lossy(&output.stderr).to_string();
+ if ctx.verbose {
+ println!("{}", stderr);
+ } else {
+ let mut skip_lines = 0;
+ for line in stderr.lines() {
+ // Check if this line starts a blacklisted message
+ if line.starts_with("Details: createItemModels") {
+ skip_lines = 5; // There are 5 lines to skip, including this one
+ }
+
+ // If skip_lines is non-zero, skip printing and decrement the counter
+ if skip_lines > 0 {
+ skip_lines -= 1;
+ continue;
+ }
+
+ println!("{}", line);
+ }
+ }
+
+ if !output.status.success() {
+ eprintln!("Failed to build project with xcodebuild. Aborting.");
+ return Err(());
+ }
+
+ //Copy build artifacts & packages into `build`
+ let swift_cart_src = pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-common")
+ .join("pax-swift-cartridge");
+ let swift_common_src = pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-common")
+ .join("pax-swift-common");
+
+ let swift_cart_build_dest = build_dest_base
+ .join("pax-chassis-common")
+ .join("pax-swift-cartridge");
+ let swift_common_build_dest = build_dest_base
+ .join("pax-chassis-common")
+ .join("pax-swift-common");
+
+ let (app_xcodeproj_src, app_xcodeproj_build_dest) = if let RunTarget::macOS = target {
+ (
+ pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-macos")
+ .join("interface")
+ .join("pax-app-macos"),
+ build_dest_base
+ .join("pax-chassis-macos")
+ .join("interface")
+ .join("pax-app-macos"),
+ )
+ } else {
+ (
+ pax_dir
+ .join(PKG_DIR_NAME)
+ .join("pax-chassis-ios")
+ .join("interface")
+ .join("pax-app-ios"),
+ build_dest_base
+ .join("pax-chassis-ios")
+ .join("interface")
+ .join("pax-app-ios"),
+ )
+ };
+
+ let _ = fs::create_dir_all(&swift_cart_build_dest);
+ let _ = fs::create_dir_all(&swift_common_build_dest);
+ let _ = fs::create_dir_all(&app_xcodeproj_build_dest);
+
+ let _ = copy_dir_recursively(
+ &swift_cart_src,
+ &swift_cart_build_dest,
+ &DIR_IGNORE_LIST_MACOS,
+ );
+ let _ = copy_dir_recursively(
+ &swift_common_src,
+ &swift_common_build_dest,
+ &DIR_IGNORE_LIST_MACOS,
+ );
+ let _ = copy_dir_recursively(
+ &app_xcodeproj_src,
+ &app_xcodeproj_build_dest,
+ &DIR_IGNORE_LIST_MACOS,
+ );
+
+ // Start `run` rather than a `build`
+ let target_str: &str = target.into();
+ if ctx.should_also_run {
+ println!("{} 🐇 Running Pax {}...", *PAX_BADGE, target_str);
+
+ if let RunTarget::macOS = target {
+ //
+ // Handle macOS `run`
+ //
+
+ let system_binary_path =
+ executable_dot_app_path.join(&format!("Contents/MacOS/{}", scheme));
+
+ let status = Command::new(system_binary_path)
+ .status() // This will wait for the process to complete
+ .expect("failed to execute the app");
+
+ println!("App exited with: {:?}", status);
+ } else {
+ //
+ // Handle iOS `run`
+ //
+
+ // Get list of devices
+ let mut cmd = Command::new("xcrun");
+ cmd.arg("simctl")
+ .arg("list")
+ .arg("-j")
+ .arg("devices")
+ .arg("available")
+ .stdout(std::process::Stdio::piped());
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+ let child = cmd.spawn().expect(ERR_SPAWN);
+ let output = wait_with_output(&process_child_ids, child);
+
+ let output_str = std::str::from_utf8(&output.stdout).map_err(|_| ())?;
+ let parsed: Value = serde_json::from_str(&output_str).map_err(|_| ())?;
+
+ // Extract devices
+ let devices = parsed["devices"]
+ .as_object()
+ .ok_or_else(|| {
+ eprintln!("Invalid JSON format for devices.");
+ ()
+ })?;
+
+ let mut max_iphone_number = 0;
+ let mut desired_udid = None;
+
+ for (_, device_list) in devices {
+ if let Some(device_array) = device_list.as_array() {
+ for device in device_array {
+ if let Some(device_type) = device["deviceTypeIdentifier"].as_str() {
+ if device_type.starts_with("com.apple.CoreSimulator.SimDeviceType.iPhone-") {
+ if let Some(number) = device_type.split('-').last() {
+ if let Ok(number) = number.parse::() {
+ if number > max_iphone_number {
+ max_iphone_number = number;
+ desired_udid = device["udid"].as_str();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ let device_udid = match desired_udid {
+ Some(udid) => udid,
+ None => {
+ eprintln!("No installed iOS simulators found on this system. Install at least one iPhone simulator through xcode and try again.");
+ return Err(());
+ }
+ };
+
+ // Open the Simulator app
+ let mut cmd = Command::new("open");
+ cmd.arg("-a")
+ .arg("Simulator")
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped());
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+ let child = cmd.spawn().expect(ERR_SPAWN);
+ let output = wait_with_output(&process_child_ids, child);
+ if !output.status.success() {
+ eprintln!("Error opening iOS simulator. Aborting.");
+ return Err(());
+ }
+
+ // Boot current device
+ let mut cmd = Command::new("xcrun");
+ cmd.arg("simctl")
+ .arg("boot")
+ .arg(device_udid)
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped());
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+ let child = cmd.spawn().expect(ERR_SPAWN);
+ let _output = wait_with_output(&process_child_ids, child);
+
+ // Boot the relevant simulator
+ let mut cmd = Command::new("xcrun");
+ cmd.arg("simctl")
+ .arg("spawn")
+ .arg(device_udid)
+ .arg("launchctl")
+ .arg("print")
+ .arg("system")
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::inherit());
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+ let child = cmd.spawn().expect(ERR_SPAWN);
+ let output = wait_with_output(&process_child_ids, child);
+ if !output.status.success() {
+ eprintln!("Error spawning iOS simulator. Aborting.");
+ return Err(());
+ }
+ // ^ Note that we don't handle errors on this particular command; it will return an error by default
+ // if the simulator isn't running, which isn't an "error" for us. Instead, defer to the following
+ // polling logic to decide whether the simulator failed to start, which would indeed be an error.
+
+ // After opening the simulator, wait for the simulator to be booted
+ let max_retries = 5;
+ let retry_period_secs = 5;
+ let mut retries = 0;
+
+ while !is_simulator_booted(device_udid, &process_child_ids)
+ && retries < max_retries
+ {
+ println!("{} 💤 Waiting for simulator to boot...", *PAX_BADGE);
+ std::thread::sleep(std::time::Duration::from_secs(retry_period_secs));
+ retries = retries + 1;
+ }
+
+ if retries == max_retries {
+ eprintln!(
+ "Failed to boot the simulator within the expected time. Aborting."
+ );
+ return Err(());
+ }
+
+ // Install and run app on simulator
+ println!(
+ "{} 📤 Installing and running app from {} on simulator...",
+ *PAX_BADGE,
+ executable_output_dir_path.to_str().unwrap()
+ );
+
+ let mut cmd = Command::new("xcrun");
+ cmd.arg("simctl")
+ .arg("install")
+ .arg(device_udid)
+ .arg(executable_dot_app_path)
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped());
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+ let child = cmd.spawn().expect(ERR_SPAWN);
+ let output = wait_with_output(&process_child_ids, child);
+ if !output.status.success() {
+ eprintln!("Error installing app on iOS simulator. Aborting.");
+ return Err(());
+ }
+
+ let mut cmd = Command::new("xcrun");
+ cmd.arg("simctl")
+ .arg("launch")
+ .arg(device_udid)
+ .arg("dev.pax.pax-app-ios")
+ .stdout(std::process::Stdio::inherit())
+ .stderr(std::process::Stdio::inherit());
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+ let child = cmd.spawn().expect(ERR_SPAWN);
+ let output = wait_with_output(&process_child_ids, child);
+ if !output.status.success() {
+ eprintln!("Error launching app on iOS simulator. Aborting.");
+ return Err(());
+ }
+ let status = output.status.code().unwrap();
+
+ println!(
+ "{} 🚀 App launched on simulator. Launch command exited with code: {:?}",
+ *PAX_BADGE, status
+ );
+ }
+ } else {
+ let build_path = executable_output_dir_path.to_str().unwrap().bold();
+ println!(
+ "{} 🗂️ Done: {} {} build available at {}",
+ *PAX_BADGE, target_str, build_mode_name, build_path
+ );
+ }
}
RunTarget::Web => {
let mut cmd = Command::new("wasm-pack");
@@ -1372,11 +1959,10 @@ pub fn build_chassis_with_cartridge(
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit());
- //approximate `should_also_run` as "dev build," `!should_also_run` as prod
- if ctx.should_also_run {
- cmd.arg("--dev");
- } else {
+ if is_release {
cmd.arg("--release");
+ } else {
+ cmd.arg("--dev");
}
#[cfg(unix)]
@@ -1384,17 +1970,88 @@ pub fn build_chassis_with_cartridge(
cmd.pre_exec(pre_exec_hook);
}
- let child = cmd.spawn().expect("failed to spawn child");
- // child.stdin.take().map(drop);
+ let child = cmd.spawn().expect(ERR_SPAWN);
+
+ // Execute wasm-pack build
let output = wait_with_output(&process_child_ids, child);
+ if !output.status.success() {
+ eprintln!("Failed to build project with wasm-pack. Aborting.");
+ return Err(());
+ }
+
+ // Copy assets
+ let asset_src = pax_dir.join("..").join(ASSETS_DIR_NAME);
+ let asset_dest = interface_path.join(PUBLIC_DIR_NAME).join(ASSETS_DIR_NAME);
+
+ // Create target assets directory
+ if let Err(e) = fs::create_dir_all(&asset_dest) {
+ eprintln!("Error creating directory {:?}: {}", asset_dest, e);
+ return Err(());
+ }
+
+ // Perform recursive copy from userland `assets/` to built `assets/`
+ if let Err(e) = copy_dir_recursively(&asset_src, &asset_dest, &vec![]) {
+ eprintln!("Error copying assets: {}", e);
+ return Err(());
+ }
- output
+ //Copy fully built project into .pax/build/web, ready for e.g. publishing
+ let build_src = interface_path.join(PUBLIC_DIR_NAME);
+ let build_dest = pax_dir
+ .join(BUILD_DIR_NAME)
+ .join(build_mode_name)
+ .join(target_str_lower);
+ let res = copy_dir_recursively(&build_src, &build_dest, &DIR_IGNORE_LIST_WEB);
+ if let Err(e) = res {
+ eprintln!(
+ "Failed to copy built files from {} to {}. {:?}",
+ &build_src.to_str().unwrap(),
+ &build_dest.to_str().unwrap(),
+ e
+ );
+ }
+
+ // Start local server if this is a `run` rather than a `build`
+ if ctx.should_also_run {
+ println!("{} 🐇 Running Pax Web...", *PAX_BADGE);
+ let _ = start_static_http_server(interface_path.join(PUBLIC_DIR_NAME));
+ } else {
+ println!(
+ "{} 🗂️ Done: {} build available at {}",
+ *PAX_BADGE,
+ build_mode_name,
+ build_dest.to_str().unwrap()
+ );
+ }
}
}
+ Ok(())
}
-static PAX_CREATE_TEMPLATE: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/new-project-template");
-const PAX_CREATE_TEMPLATE_DIR_NAME: &str = "new-project-template";
+// This function checks if the simulator with the given UDID is booted
+fn is_simulator_booted(device_udid: &str, process_child_ids: &Arc>>) -> bool {
+ let mut cmd = Command::new("xcrun");
+ cmd.arg("simctl")
+ .arg("list")
+ .arg("devices")
+ .stdout(std::process::Stdio::piped())
+ .stderr(std::process::Stdio::piped());
+
+ #[cfg(unix)]
+ unsafe {
+ cmd.pre_exec(pre_exec_hook);
+ }
+ let child = cmd.spawn().expect(ERR_SPAWN);
+ let output = wait_with_output(&process_child_ids, child);
+ if !output.status.success() {
+ panic!("Error checking simulator status. This is an unhandled error and may leave orphaned processes.");
+ }
+
+ let output_str = String::from_utf8(output.stdout).expect("Failed to convert to string");
+ output_str
+ .lines()
+ .any(|line| line.contains(device_udid) && line.contains("Booted"))
+}
pub fn perform_create(ctx: &CreateContext) {
let full_path = Path::new(&ctx.path);
@@ -1534,18 +2191,23 @@ pub struct RunContext {
pub should_also_run: bool,
pub is_libdev_mode: bool,
pub process_child_ids: Arc>>,
+ pub is_release: bool,
}
pub enum RunTarget {
- MacOS,
+ #[allow(non_camel_case_types)]
+ macOS,
Web,
+ #[allow(non_camel_case_types)]
+ iOS,
}
impl From<&str> for RunTarget {
fn from(input: &str) -> Self {
match input.to_lowercase().as_str() {
- "macos" => RunTarget::MacOS,
+ "macos" => RunTarget::macOS,
"web" => RunTarget::Web,
+ "ios" => RunTarget::iOS,
_ => {
unreachable!()
}
@@ -1557,7 +2219,8 @@ impl<'a> Into<&'a str> for &'a RunTarget {
fn into(self) -> &'a str {
match self {
RunTarget::Web => "Web",
- RunTarget::MacOS => "MacOS",
+ RunTarget::macOS => "macOS",
+ RunTarget::iOS => "iOS",
}
}
}
@@ -1592,21 +2255,28 @@ impl Ord for NamespaceTrieNode {
}
}
-const ERR_ASYNC: &str = "Expected synchronous execution; encountered async execution";
+const ERR_LOCK: &str = "Failed to lock process_child_ids mutex";
+
pub fn wait_with_output(
process_child_ids: &Arc>>,
child: std::process::Child,
) -> std::process::Output {
let child_id: u64 = child.id().into();
- process_child_ids.lock().expect(ERR_ASYNC).push(child_id);
+
+ // Push the child_id to the shared process_child_ids vector
+ process_child_ids.lock().expect(ERR_LOCK).push(child_id);
+
+ // Wait for the child process to complete
let output = child
.wait_with_output()
.expect("Failed to wait for child process");
- assert!(
- process_child_ids.lock().expect(ERR_ASYNC).pop().unwrap() == child_id,
- "{}",
- ERR_ASYNC
- );
+
+ // Ensure the child ID is removed after completion
+ process_child_ids
+ .lock()
+ .expect(ERR_LOCK)
+ .retain(|&id| id != child_id);
+
output
}
diff --git a/pax-compiler/src/parsing.rs b/pax-compiler/src/parsing.rs
index f1a9657e5..61011e8ac 100644
--- a/pax-compiler/src/parsing.rs
+++ b/pax-compiler/src/parsing.rs
@@ -847,14 +847,13 @@ impl Default for ParsingContext {
}
}
-
#[derive(Debug)]
pub struct ParsingError {
pub error_name: String,
pub error_message: String,
pub matched_string: String,
pub start: (usize, usize),
- pub end: (usize, usize),
+ pub end: (usize, usize),
}
/// Extract all errors from a Pax parse result
@@ -891,7 +890,7 @@ pub fn extract_errors(pairs: pest::iterators::Pairs) -> Vec
format!("{:?}", pair.as_rule()),
"Open tag is malformed".to_string(),
)),
- Rule::tag_error => Some((
+ Rule::tag_error => Some((
format!("{:?}", pair.as_rule()),
"Tag structure is unexpected.".to_string(),
)),
@@ -899,7 +898,8 @@ pub fn extract_errors(pairs: pest::iterators::Pairs) -> Vec
};
if let Some((error_name, error_message)) = error {
let span = pair.as_span();
- let ((line_start, start_col), (line_end, end_col)) = (pair.line_col(),span.end_pos().line_col());
+ let ((line_start, start_col), (line_end, end_col)) =
+ (pair.line_col(), span.end_pos().line_col());
let error = ParsingError {
error_name,
error_message,
@@ -909,7 +909,7 @@ pub fn extract_errors(pairs: pest::iterators::Pairs) -> Vec
};
errors.push(error);
}
- errors.extend(extract_errors(pair.into_inner()));
+ errors.extend(extract_errors(pair.into_inner()));
}
errors
@@ -929,27 +929,27 @@ pub fn assemble_component_definition(
.expect(&format!("unsuccessful parse from {}", &pax)) // unwrap the parse result
.next()
.unwrap(); // get and unwrap the `pax_component_definition` rule
-
- let errors = extract_errors(_ast.clone().into_inner());
- if !errors.is_empty() {
- let mut error_messages = String::new();
-
- for error in &errors {
- let msg = format!(
- "error: {}\n --> {}:{}\n |\n{} | {}\n |{}\n\n",
- error.error_message,
- error.start.0,
- error.start.1,
- error.start.0,
- error.matched_string,
- "^".repeat(error.matched_string.len())
- );
- error_messages.push_str(&msg);
- }
-
- panic!("{}", error_messages);
+
+ let errors = extract_errors(_ast.clone().into_inner());
+ if !errors.is_empty() {
+ let mut error_messages = String::new();
+
+ for error in &errors {
+ let msg = format!(
+ "error: {}\n --> {}:{}\n |\n{} | {}\n |{}\n\n",
+ error.error_message,
+ error.start.0,
+ error.start.1,
+ error.start.0,
+ error.matched_string,
+ "^".repeat(error.matched_string.len())
+ );
+ error_messages.push_str(&msg);
}
-
+
+ panic!("{}", error_messages);
+ }
+
if is_main_component {
ctx.main_component_type_id = self_type_id.to_string();
}
@@ -1279,7 +1279,6 @@ impl Reflectable for pax_runtime_api::Numeric {
}
}
-
impl Reflectable for pax_runtime_api::SizePixels {
fn get_import_path() -> String {
"pax_lang::api::SizePixels".to_string()
diff --git a/pax-compiler/src/templating.rs b/pax-compiler/src/templating.rs
index f67f73231..70041362f 100644
--- a/pax-compiler/src/templating.rs
+++ b/pax-compiler/src/templating.rs
@@ -4,8 +4,7 @@ use serde_derive::{Deserialize, Serialize};
#[allow(unused_imports)]
use serde_json;
use std::collections::HashMap;
-use tera::{Tera, Context};
-
+use tera::{Context, Tera};
use crate::manifest::{ExpressionSpec, PropertyDefinition};
@@ -137,12 +136,12 @@ pub fn press_template_codegen_cartridge_render_node_literal(
.unwrap();
let mut tera = Tera::default();
- tera.add_raw_template("cartridge-render-node-literal", template).unwrap();
+ tera.add_raw_template("cartridge-render-node-literal", template)
+ .unwrap();
tera.render(
"cartridge-render-node-literal",
&Context::from_serialize(args).unwrap(),
)
- .unwrap()
+ .unwrap()
}
-
diff --git a/pax-core/src/component.rs b/pax-core/src/component.rs
index a54aaf475..d92ff4cfb 100644
--- a/pax-core/src/component.rs
+++ b/pax-core/src/component.rs
@@ -90,9 +90,6 @@ impl RenderNode for ComponentInstance {
bounds
}
fn compute_properties(&mut self, rtc: &mut RenderTreeContext) {
- self.common_properties.compute_properties(rtc);
-
- (*self.compute_properties_fn)(Rc::clone(&self.properties), rtc);
//expand adoptees before adding to stack frame.
//NOTE: this requires *evaluating properties* for `should_flatten` nodes like Repeat and Conditional, whose
@@ -109,10 +106,13 @@ impl RenderNode for ComponentInstance {
));
(*rtc.runtime).borrow_mut().push_stack_frame(
- flattened_adoptees,
+ Rc::clone(&flattened_adoptees),
Rc::clone(&self.properties),
self.timeline.clone(),
);
+
+ self.common_properties.compute_properties(rtc);
+ (*self.compute_properties_fn)(Rc::clone(&self.properties), rtc);
}
fn get_layer_type(&mut self) -> Layer {
diff --git a/pax-core/src/engine.rs b/pax-core/src/engine.rs
index d725a4aa8..312f83a23 100644
--- a/pax-core/src/engine.rs
+++ b/pax-core/src/engine.rs
@@ -1061,6 +1061,9 @@ impl PaxEngine {
}
}
+ //lifecycle: did_render
+ node.borrow_mut().handle_did_render(rtc, rcs);
+
//Handle node unmounting
if marked_for_unmount {
//lifecycle: will_unmount
@@ -1070,11 +1073,8 @@ impl PaxEngine {
self.instance_registry
.borrow_mut()
.mounted_set
- .remove(&id_chain); //, "Tried to unmount a node, but it was not mounted");
+ .remove(&id_chain);
}
-
- //lifecycle: did_render
- node.borrow_mut().handle_did_render(rtc, rcs);
}
/// Simple 2D raycasting: the coordinates of the ray represent a
diff --git a/pax-core/src/runtime.rs b/pax-core/src/runtime.rs
index b4540ba36..03ec610c6 100644
--- a/pax-core/src/runtime.rs
+++ b/pax-core/src/runtime.rs
@@ -119,7 +119,7 @@ impl Runtime {
/// Handles special-cases like `for`/`Repeat`, where properties for the
/// control flow primitive need to be computed out-of-lifecycle, and where nested child elements
/// need to be treated as top-level elements.
- /// For example, for `for i in (0..3){ }`,
+ /// For example, given `for i in (0..3){ }`,
/// without this special handling `Stacker` will receive only two adoptees: the `Ellipse` and the `Repeat` node
/// created by `for`. In other words `for`s children need to be treated as ``s children,
/// and this processing allows that to happpen.
@@ -131,8 +131,8 @@ impl Runtime {
) -> Vec> {
let mut adoptee_borrowed = (**adoptee).borrow_mut();
if adoptee_borrowed.should_flatten() {
- //1. this is an `if` or `for` (etc.) — it needs its properties computed
- // in order for its children to be correct
+ // //1. this is an `if` or `for` (etc.) — it needs its properties computed
+ // // in order for its children to be correct
adoptee_borrowed.compute_properties(rtc);
//2. recurse into top-level should_flatten() nodes
(*adoptee_borrowed.get_rendering_children())
@@ -143,14 +143,13 @@ impl Runtime {
})
.flatten()
.collect()
- //NOTE: probably worth optimizing (pending profiling.) Lots of allocation happening here -- flattening and collecting `Vec`s is probably not
- //the most efficient possible approach, and this is fairly hot-running code.
} else {
vec![Rc::clone(adoptee)]
}
}
}
+
/// Data structure for a single frame of our runtime stack, including
/// a reference to its parent frame, a list of `adoptees` for
/// prospective [`Slot`] consumption, and `properties` for
diff --git a/pax-example/components/color_grid.pax b/pax-example/components/color_grid.pax
new file mode 100644
index 000000000..958ea644f
--- /dev/null
+++ b/pax-example/components/color_grid.pax
@@ -0,0 +1,9 @@
+for i in 0..10 {
+
+ for j in 0..10 {
+
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/pax-example/pax b/pax-example/pax
index a29ea90fa..b6606002b 100755
--- a/pax-example/pax
+++ b/pax-example/pax
@@ -1,12 +1,14 @@
#!/bin/bash
-### Helper binary for pax libdev, allowing pax-cli-like ergonomics inside the pax-example directory
+### Helper script for pax libdev, allowing pax-cli-like ergonomics inside the pax-example directory
+###
### For example, from @/pax root:
### `cd pax-example && ./pax run --target=macos`
### `cd pax-example && ./pax parse`
### `cd pax-example && ./pax libdev build-chassis`
+
set -e
pushd ../pax-cli
cargo build
../target/debug/pax-cli "$@" --path="../pax-example" --libdev
-popd
\ No newline at end of file
+popd
diff --git a/pax-std/pax-std-primitives/src/text.rs b/pax-std/pax-std-primitives/src/text.rs
index c25115b53..fa18c64cc 100644
--- a/pax-std/pax-std-primitives/src/text.rs
+++ b/pax-std/pax-std-primitives/src/text.rs
@@ -61,6 +61,7 @@ impl RenderNode for TextInstance {
Rc::new(RefCell::new(vec![]))
}
fn compute_properties(&mut self, rtc: &mut RenderTreeContext) {
+
let properties = &mut *self.properties.as_ref().borrow_mut();
if let Some(text) = rtc.compute_vtable_value(properties.text._get_vtable_id()) {
diff --git a/scripts/print-dag.py b/scripts/print-dag.py
index 73dda0cfb..fa5438f13 100755
--- a/scripts/print-dag.py
+++ b/scripts/print-dag.py
@@ -6,7 +6,9 @@
PACKAGES = [
"pax-cartridge",
+ "pax-chassis-common",
"pax-chassis-macos",
+ "pax-chassis-web",
"pax-cli",
"pax-compiler",
"pax-core",
diff --git a/scripts/release.py b/scripts/release.py
index 99d038ad0..2ffbb398c 100755
--- a/scripts/release.py
+++ b/scripts/release.py
@@ -24,6 +24,7 @@
PACKAGES = [
"pax-cartridge",
+ "pax-chassis-common",
"pax-chassis-macos",
"pax-chassis-web",
"pax-cli",