From e0cf737fdc9f59f02b858c94fa8f5c8b315161e1 Mon Sep 17 00:00:00 2001 From: Jiawen Chen Date: Mon, 18 Nov 2024 08:53:57 -0800 Subject: [PATCH] Adds using Swift from C++ example --- examples/xplatform/swift_from_cxx/BUILD | 17 ++++ .../xplatform/swift_from_cxx/Landscape.swift | 40 ++++++++ .../swift_from_cxx/landscape_cxx_client.cpp | 93 +++++++++++++++++++ 3 files changed, 150 insertions(+) create mode 100644 examples/xplatform/swift_from_cxx/BUILD create mode 100644 examples/xplatform/swift_from_cxx/Landscape.swift create mode 100644 examples/xplatform/swift_from_cxx/landscape_cxx_client.cpp diff --git a/examples/xplatform/swift_from_cxx/BUILD b/examples/xplatform/swift_from_cxx/BUILD new file mode 100644 index 000000000..fb22b6e3a --- /dev/null +++ b/examples/xplatform/swift_from_cxx/BUILD @@ -0,0 +1,17 @@ +load("//swift:swift_library.bzl", "swift_library") + +swift_library( + name = "landscape", + srcs = ["Landscape.swift"], + copts = ["-cxx-interoperability-mode=default"], + # Auto-generates landscape-Swift.h. + # It can be customized with generated_header_name. + generates_header = True, + module_name = "SwiftLandscape", +) + +cc_binary( + name = "landscape_cxx_client", + srcs = ["landscape_cxx_client.cpp"], + deps = [":landscape"], +) diff --git a/examples/xplatform/swift_from_cxx/Landscape.swift b/examples/xplatform/swift_from_cxx/Landscape.swift new file mode 100644 index 000000000..ad9b905f3 --- /dev/null +++ b/examples/xplatform/swift_from_cxx/Landscape.swift @@ -0,0 +1,40 @@ +public struct MountainPeak { + let name: String + let height: Float + + public init(name: String, height: Float) { + self.name = name + self.height = height + } + + public func printDescription() { + print("Peak: \(name), height: \(height)") + } +} + +public class MountainRange { + let peaks: [MountainPeak] + + public init(peaks: [MountainPeak]) { + self.peaks = peaks + } + + public func printPeaks() { + print("Peaks in range:") + for peak in peaks { + peak.printDescription() + } + } +} + +// Simple enum. +public enum VolcanoStatus { + case dormant + case active +} + +// enum with associated values. +public enum LandmarkIdentifier { + case name(String) + case id(Int) +} diff --git a/examples/xplatform/swift_from_cxx/landscape_cxx_client.cpp b/examples/xplatform/swift_from_cxx/landscape_cxx_client.cpp new file mode 100644 index 000000000..cfdcd9120 --- /dev/null +++ b/examples/xplatform/swift_from_cxx/landscape_cxx_client.cpp @@ -0,0 +1,93 @@ +#include + +#include "examples/xplatform/swift_from_cxx/landscape-Swift.h" + +// The Swift module "SwiftLandscape" is imported as the C++ namespace +// "SwiftLandscape". + +SwiftLandscape::VolcanoStatus invertVolcanoStatus( + SwiftLandscape::VolcanoStatus status) { + switch (status) { + case SwiftLandscape::VolcanoStatus::dormant: + // Returns `VolcanoStatus.active` case. + return SwiftLandscape::VolcanoStatus::active(); + case SwiftLandscape::VolcanoStatus::active: + // Returns `VolcanoStatus.dormant` case. + return SwiftLandscape::VolcanoStatus::dormant(); + } +} + +void printLandmarkIdentifier(SwiftLandscape::LandmarkIdentifier identifier) { + switch (identifier) { + case SwiftLandscape::LandmarkIdentifier::name: + std::cout << (std::string)identifier.getName() << std::endl; + break; + case SwiftLandscape::LandmarkIdentifier::id: + std::cout << "unnamed landmark #" << identifier.getId() << std::endl; + break; + } +} + +void structsAndClasses() { + std::cout << "----- Swift structs and classes in C++ -----" << std::endl; + + // SwiftLandscape::MountainPeak is a Swift struct. But you must still use + // init(), because Swift initializers are not the same as C++ + // constructors. + SwiftLandscape::MountainPeak mount_everest = + SwiftLandscape::MountainPeak::init("Mount Everest", 8848.0f); + + // You can call a Swift struct member function from C++. + mount_everest.printDescription(); + + // Swift arrays are mapped to swift::Array in C++. + auto peaks = swift::Array::init(); + { + SwiftLandscape::MountainPeak k2 = + SwiftLandscape::MountainPeak::init("K2", 8611.0f); + peaks.append(mount_everest); + peaks.append(k2); + } + + SwiftLandscape::MountainRange himalayas = + SwiftLandscape::MountainRange::init(peaks); + + himalayas.printPeaks(); +} + +void simpleEnums() { + std::cout << "----- Simple Swift enums -----" << std::endl; + auto dormant = SwiftLandscape::VolcanoStatus::dormant(); + auto active = SwiftLandscape::VolcanoStatus::active(); + + std::cout << "dormant has C++ int value: " + << static_cast(SwiftLandscape::VolcanoStatus::cases::dormant) + << std::endl; + std::cout << "active has C++ int value: " + << static_cast(SwiftLandscape::VolcanoStatus::cases::active) + << std::endl; + + auto inverted = invertVolcanoStatus(dormant); + std::cout << "inverted(dormant) == active? -> " + << ((inverted == active) ? "true" : "false") << std::endl; +} + +void enumsWithAssociatedTypes() { + std::cout << "----- Swift enums with associated types -----" << std::endl; + auto new_landmark_id = SwiftLandscape::LandmarkIdentifier::id(1234); + printLandmarkIdentifier(new_landmark_id); + + auto new_landmark_name = + SwiftLandscape::LandmarkIdentifier::name("Eiffel Tower"); + printLandmarkIdentifier(new_landmark_name); +} + +int main(int argc, char* argv[]) { + structsAndClasses(); + + simpleEnums(); + + enumsWithAssociatedTypes(); + + return 0; +}