Add SwiftUI demo

This commit is contained in:
Jelle Besseling 2022-08-27 22:39:19 +02:00
parent 6e19ca1da6
commit f7b2a73a75
No known key found for this signature in database
GPG key ID: 9712452E8BE3372E
7 changed files with 130 additions and 3 deletions

View file

@ -297,7 +297,7 @@ mod cli_run {
let file_name = example_file(dir_name, example.filename);
match example.executable_filename {
"form" | "hello-gui" | "breakout" | "ruby" => {
"form" | "hello-gui" | "breakout" | "ruby" | "swiftui" => {
// Since these require things the build system often doesn't have
// (e.g. GUIs open a window, Ruby needs ruby installed, WASM needs a browser)
// we do `roc build` on them but don't run them.
@ -548,6 +548,14 @@ mod cli_run {
use_valgrind: false,
}
},
swiftui:"swiftui" => Example {
filename: "main.roc",
executable_filename: "swiftui",
stdin: &[],
input_file: None,
expected_ending: "",
use_valgrind: false,
},
}
macro_rules! benchmarks {

View file

@ -423,6 +423,7 @@ pub fn build_c_host_native(
command.output().unwrap()
}
#[allow(clippy::too_many_arguments)]
pub fn build_swift_host_native(
env_path: &str,
env_home: &str,
@ -431,16 +432,25 @@ pub fn build_swift_host_native(
opt_level: OptLevel,
shared_lib_path: Option<&Path>,
objc_header_path: Option<&str>,
arch: Architecture,
) -> Output {
if shared_lib_path.is_some() {
unimplemented!("Linking a shared library to Swift not yet implemented");
}
let mut command = Command::new("xcrun"); // xcrun helps swiftc to find the right header files
let mut command = Command::new("arch");
command
.env_clear()
.env("PATH", &env_path)
.env("HOME", &env_home)
.env("HOME", &env_home);
match arch {
Architecture::Aarch64(_) => command.arg("-arm64"),
_ => command.arg(format!("-{}", arch)),
};
command
.arg("xcrun") // xcrun helps swiftc to find the right header files
.arg("swiftc")
.args(sources)
.arg("-emit-object")
@ -734,6 +744,7 @@ pub fn rebuild_host(
swift_host_header_src
.exists()
.then(|| swift_host_header_src.to_str().unwrap()),
target.architecture,
);
validate_output("host.swift", "swiftc", output);
}

View file

@ -0,0 +1,6 @@
app "swiftui"
packages { pf: "platform/main.roc" }
imports []
provides [main] to pf
main = "Roc <3 Swift!\n"

View file

@ -0,0 +1,9 @@
#include <stdlib.h>
struct RocStr {
char* bytes;
size_t len;
size_t capacity;
};
extern void roc__mainForHost_1_exposed_generic(const struct RocStr *data);

View file

@ -0,0 +1,78 @@
import Foundation
import SwiftUI
@_cdecl("roc_alloc")
func rocAlloc(size: Int, _alignment: UInt) -> UInt {
guard let ptr = malloc(size) else {
return 0
}
return UInt(bitPattern: ptr)
}
@_cdecl("roc_dealloc")
func rocDealloc(ptr: UInt, _alignment: UInt) {
free(UnsafeMutableRawPointer(bitPattern: ptr))
}
@_cdecl("roc_realloc")
func rocRealloc(ptr: UInt, _oldSize: Int, newSize: Int, _alignment: UInt) -> UInt {
guard let ptr = realloc(UnsafeMutableRawPointer(bitPattern: ptr), newSize) else {
return 0
}
return UInt(bitPattern: ptr)
}
func isSmallString(rocStr: RocStr) -> Bool {
return rocStr.capacity < 0
}
func getStrLen(rocStr: RocStr) -> Int {
if isSmallString(rocStr: rocStr) {
// Small String length is last in the byte of capacity.
var cap = rocStr.capacity
let count = MemoryLayout.size(ofValue: cap)
let bytes = Data(bytes: &cap, count: count)
let lastByte = bytes[count - 1]
return Int(lastByte ^ 0b1000_0000)
} else {
return rocStr.len
}
}
func getSwiftString(rocStr: RocStr) -> String {
let length = getStrLen(rocStr: rocStr)
if isSmallString(rocStr: rocStr) {
let data: Data = withUnsafePointer(to: rocStr) { ptr in
Data(bytes: ptr, count: length)
}
return String(data: data, encoding: .utf8)!
} else {
let data = Data(bytes: rocStr.bytes, count: length)
return String(data: data, encoding: .utf8)!
}
}
struct ContentView: View {
var str: String
init() {
var rocStr = RocStr()
roc__mainForHost_1_exposed_generic(&rocStr)
self.str = getSwiftString(rocStr: rocStr)
}
var body: some View {
Text(self.str)
.padding()
}
}
@main
struct RocTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}

View file

@ -0,0 +1,9 @@
platform "swiftui-platform"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main

6
examples/swiftui/run.sh Executable file
View file

@ -0,0 +1,6 @@
#! /usr/bin/env bash
cargo run -- build
mkdir -p SwiftUIDemo.app/Contents/MacOS/
mv swiftui SwiftUIDemo.app/Contents/MacOS/SwiftUIDemo
open SwiftUIDemo.app