Skip to content
This repository was archived by the owner on Dec 21, 2023. It is now read-only.

[WIP] Proof-of-concept integration of pure swift model into TuriCreate #2878

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
[WIP] Working prototype of swift model integrated into TuriCreate.
This adds an XCode project that demonstrates how to effectively write a
swift ML model while allowing it to be called from C++ or python.

The key idea is to expose the swift class to objective-C (add @objc
modifier), then write a simple Objective-C++ class that is registered
using the new model registration mechanism.  The type convesion is handled by
overloading the variant_type converter to handle native Objective-C
types.

See src/xcode_swift_toolkit/TC_Swift_Demo/TC_Swift_Demo.xcodeproj for a
proof of concept.
Hoyt Koepke committed Dec 24, 2019
commit 850e8124c4c74df8fac1dd07e3ff65533d1b47eb
8 changes: 1 addition & 7 deletions src/model_server/lib/variant.hpp
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@
#include <core/data/flexible_type/flexible_type.hpp>
#include <core/storage/sframe_data/dataframe.hpp>
#include <core/storage/serialization/serialization_includes.hpp>
#include <model_server/lib/variant.hpp>

namespace turi {
class model_base;
@@ -308,13 +309,6 @@ template <typename T>
inline variant_type to_variant(const T& f) {
return variant_converter<typename std::decay<T>::type>().set(f);
}

/** Overload for the case when we're trying to wrap a void return
* type in a template.
*/
inline variant_type to_variant() {
return variant_type();
}
} // namespace turi

namespace turi {
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//
// Wrapper.m
// TC_Swift_Demo
//
// Created by Hoyt Koepke on 12/23/19.
// Copyright © 2019 Hoyt Koepke. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "TC_Swift_Demo/TC_Swift_Demo-Swift.h"

#include <model_server_v2/model_base.hpp>
#include <model_server_v2/model_server.hpp>
#include <model_server_v2/registration.hpp>


namespace turi {

// TODO: Make an Objective-C variant converter library.
template <>
struct variant_converter<NSString*, void> {
static constexpr bool value = true;
NSString* _Nonnull get(const variant_type& val) {
return @(variant_get_ref<flexible_type>(val).get<flex_string>().c_str());
}
variant_type set(NSString* val) {
return to_variant([val UTF8String]);
}
};

class Wrapper : public turi::v2::model_base {
public:

SwiftMLClass* m;

Wrapper() {
m = [[SwiftMLClass alloc] init];

register_method("append_string", &Wrapper::append_string, "s");
register_method("get_string", &Wrapper::get_string);
}

const char* name() const override {
return "SwiftWrapperTest";
}

void append_string(NSString* _Nonnull s) {
[m append_stringWithX:s];
}

NSString* get_string() const {
NSString* _Nonnull r = [m get_string];
return r;
}

};

REGISTER_MODEL(Wrapper);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// WrapperTests.m
// TC_Swift_DemoTests
//
// Created by Hoyt Koepke on 12/23/19.
// Copyright © 2019 Hoyt Koepke. All rights reserved.
//

#import <XCTest/XCTest.h>

#include <model_server_v2/model_server.hpp>

using namespace turi;
using namespace turi::v2;

@interface WrapperTests : XCTestCase

@end

@implementation WrapperTests



- (void)testWrapping {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.

auto m = model_server().create_model("SwiftWrapperTest");

m->call_method("append_string", "This");
m->call_method("append_string", " is");
m->call_method("append_string", " Fun!");

std::string result = variant_get_value<std::string>(m->call_method("get_string"));

XCTAssert(result == "This is Fun!");
}


@end

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions src/xcode_swift_toolkit/TC_Swift_Demo/TC_Swift_Demo/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 Hoyt Koepke. All rights reserved.</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//
// SwiftMLClass.swift
// TC_Swift_Demo
//
// Created by Hoyt Koepke on 12/23/19.
// Copyright © 2019 Hoyt Koepke. All rights reserved.
//

import Foundation


@objc public class SwiftMLClass : NSObject {
var s: String

public override init() { // Constructor
self.s = ""
super.init()
}

@objc public func append_string(x: String) {
self.s += x
print("New string: \(self.s)")
}

@objc public func get_string() -> String {
return self.s
}
}