diff --git a/Package.resolved b/Package.resolved index d7fcfa3c..96962bb2 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "50661037ace32d27f5b63e569f8fa2ccff6d3226fa694da9fc389c49efd15ddd", + "originHash" : "18d78a641a729a881369f12bb5a8ed756f270457dc57b6490548b38073085243", "pins" : [ { "identity" : "darwinprivateframeworks", @@ -7,7 +7,7 @@ "location" : "https://github.com/OpenSwiftUIProject/DarwinPrivateFrameworks.git", "state" : { "branch" : "main", - "revision" : "2af08467b97287e94093e41b8737916a8f383870" + "revision" : "eaf7097192194bbd2473dcbc3d9152e3a6d428e0" } }, { diff --git a/Package.swift b/Package.swift index 02a70812..e3913e09 100644 --- a/Package.swift +++ b/Package.swift @@ -147,6 +147,9 @@ let openGraphSPITarget = Target.target( name: "OpenGraph_SPI", cSettings: sharedCSettings + [ .define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)), + ], + linkerSettings: [ + .linkedLibrary("z"), ] ) let openGraphShimsTarget = Target.target( diff --git a/Sources/OpenGraph/Graph/Graph.swift b/Sources/OpenGraph/Graph/Graph.swift index bfd33f49..6c42100d 100644 --- a/Sources/OpenGraph/Graph/Graph.swift +++ b/Sources/OpenGraph/Graph/Graph.swift @@ -71,3 +71,33 @@ extension Graph { @inlinable public static func setOutputValue(_ value: UnsafePointer) } + +#if canImport(Darwin) +import Foundation +#endif + +extension Graph { + public func archiveJSON(name: String?) { + #if canImport(Darwin) + let options: NSDictionary = [ + Graph.descriptionFormat: "graph/dict", + Graph.descriptionIncludeValues: true, + ] + guard let description = Graph.description(self, options: options) as? [String: Any] else { + return + } + var name = name ?? "graph" + name.append(".ag-json") + let path = (NSTemporaryDirectory() as NSString).appendingPathComponent(name) + guard let data = try? JSONSerialization.data(withJSONObject: description, options: []) else { + return + } + let url = URL(fileURLWithPath: path) + do { + try data.write(to: url, options: []) + print("Wrote graph data to \"\(path)\".") + } catch { + } + #endif + } +} diff --git a/Sources/OpenGraphShims/Graph+Debug.swift b/Sources/OpenGraphShims/Graph+Debug.swift index b0f47da7..830685f6 100644 --- a/Sources/OpenGraphShims/Graph+Debug.swift +++ b/Sources/OpenGraphShims/Graph+Debug.swift @@ -9,7 +9,9 @@ import Foundation @_spi(Debug) extension Graph { public var dict: [String: Any]? { - let options = ["format": "graph/dict"] as NSDictionary + let options = [ + Graph.descriptionFormat: Graph.descriptionFormatDictionary + ] as NSDictionary guard let description = Graph.description(nil, options: options) else { return nil } @@ -25,7 +27,9 @@ extension Graph { // color: // - red: is_changed public var dot: String? { - let options = ["format": "graph/dot"] as NSDictionary + let options = [ + Graph.descriptionFormat: Graph.descriptionFormatDot + ] as NSDictionary guard let description = Graph.description(self, options: options) else { return nil diff --git a/Sources/OpenGraph_SPI/Attribute/AttributeID.hpp b/Sources/OpenGraph_SPI/Attribute/AttributeID.hpp index f64465f0..de4138ca 100644 --- a/Sources/OpenGraph_SPI/Attribute/AttributeID.hpp +++ b/Sources/OpenGraph_SPI/Attribute/AttributeID.hpp @@ -22,7 +22,7 @@ class AttributeID final { enum class Kind: uint8_t { Direct = 0x0, Indirect = 0x1, - Nil = 0x2, + Null = 0x2, }; private: uint32_t _rawValue; @@ -59,8 +59,8 @@ class AttributeID final { } OG_INLINE OG_CONSTEXPR - const bool isNil() const OG_NOEXCEPT { - return getKind() == Kind::Nil; + const bool isNull() const OG_NOEXCEPT { + return getKind() == Kind::Null; } OG_INLINE OG_CONSTEXPR diff --git a/Sources/OpenGraph_SPI/Attribute/OGAttribute.cpp b/Sources/OpenGraph_SPI/Attribute/OGAttribute.cpp index 0b0c8e01..2008742d 100644 --- a/Sources/OpenGraph_SPI/Attribute/OGAttribute.cpp +++ b/Sources/OpenGraph_SPI/Attribute/OGAttribute.cpp @@ -11,7 +11,7 @@ #include "../Util/assert.hpp" #include -const OGAttribute OGAttributeNil = OGAttribute(OG::AttributeID::Kind::Nil); +const OGAttribute OGAttributeNil = OGAttribute(OG::AttributeID::Kind::Null); OGAttribute OGGraphGetCurrentAttribute() { // TODO diff --git a/Sources/OpenGraph_SPI/Debug/og-debug-server.mm b/Sources/OpenGraph_SPI/Debug/og-debug-server.mm index 9a0db8b5..1b5e6a56 100644 --- a/Sources/OpenGraph_SPI/Debug/og-debug-server.mm +++ b/Sources/OpenGraph_SPI/Debug/og-debug-server.mm @@ -202,7 +202,7 @@ NSString *command = dic[@"command"]; if ([command isEqual:@"graph/description"]) { NSMutableDictionary *mutableDic = [NSMutableDictionary dictionaryWithDictionary:dic]; - mutableDic[(__bridge NSString *)OGDescriptionFormat] = @"graph/dict"; + mutableDic[(__bridge NSString *)OGDescriptionFormat] = (__bridge NSString *)OGDescriptionFormatDictionary; CFTypeRef description = OG::Graph::description(nullptr, mutableDic); if (description) { NSData *descriptionData = [NSJSONSerialization dataWithJSONObject:(__bridge id)description options:0 error:NULL]; diff --git a/Sources/OpenGraph_SPI/Graph/Graph.cpp b/Sources/OpenGraph_SPI/Graph/Graph.cpp index 6b1cadcb..73c81a6f 100644 --- a/Sources/OpenGraph_SPI/Graph/Graph.cpp +++ b/Sources/OpenGraph_SPI/Graph/Graph.cpp @@ -1,23 +1,22 @@ // // Graph.cpp -// -// -// Created by Kyle on 2024/1/18. -// +// OpenGraph_SPI #include "Graph.hpp" #include "Subgraph.hpp" +#include "OGGraphDescription.h" #if !OG_TARGET_OS_WASI #include #endif + #include pthread_key_t OG::Graph::_current_update_key; OG::Graph::Graph() OG_NOEXCEPT { // TODO - + // libdispatch is not supported on WASI // Tracked via https://github.com/swiftwasm/swift/issues/5565 #if !OG_TARGET_OS_WASI @@ -27,7 +26,7 @@ OG::Graph::Graph() OG_NOEXCEPT { OG::Subgraph::make_current_subgraph_key(); }); #endif - + // TODO } @@ -48,10 +47,6 @@ void OG::Graph::stop_profiling() OG_NOEXCEPT { // TODO } -void OG::Graph::write_to_file(const Graph * _Nullable, const char * _Nullable) OG_NOEXCEPT { - // TODO -} - const bool OG::Graph::thread_is_updating() const OG_NOEXCEPT { void *current = pthread_getspecific(current_key()); if (!current) { diff --git a/Sources/OpenGraph_SPI/Graph/Graph.hpp b/Sources/OpenGraph_SPI/Graph/Graph.hpp index cf5055de..5921b86d 100644 --- a/Sources/OpenGraph_SPI/Graph/Graph.hpp +++ b/Sources/OpenGraph_SPI/Graph/Graph.hpp @@ -1,9 +1,7 @@ // // Graph.hpp -// -// -// Created by Kyle on 2024/1/18. -// +// OpenGraph_SPI + #ifndef Graph_hpp #define Graph_hpp @@ -122,9 +120,11 @@ class Graph final { static void all_stop_profiling() OG_NOEXCEPT; void start_profiling(uint32_t) OG_NOEXCEPT; void stop_profiling() OG_NOEXCEPT; - - static void write_to_file(const Graph * _Nullable, const char * _Nullable) OG_NOEXCEPT; - + + #if OG_OBJC_FOUNDATION + static void write_to_file(const Graph * _Nullable, const char * _Nullable, uint8_t) OG_NOEXCEPT; + #endif + const bool thread_is_updating() const OG_NOEXCEPT; const bool is_context_updating(const OG::Graph::Context&) const OG_NOEXCEPT; diff --git a/Sources/OpenGraph_SPI/Graph/Graph.mm b/Sources/OpenGraph_SPI/Graph/Graph.mm new file mode 100644 index 00000000..fd48afaa --- /dev/null +++ b/Sources/OpenGraph_SPI/Graph/Graph.mm @@ -0,0 +1,59 @@ +// +// Graph.mm +// OpenGraph_SPI + +#include "Graph.hpp" +#include "OGGraphDescription.h" + +#if OG_OBJC_FOUNDATION +#include +#include + +void OG::Graph::write_to_file(const Graph * _Nullable graph, const char * _Nullable name, uint8_t options) OG_NOEXCEPT { + @autoreleasepool { + NSDictionary *options_dict = @{ + (__bridge NSString *)OGDescriptionFormat: (__bridge NSString *)OGDescriptionFormatDictionary, + (__bridge NSString *)OGDescriptionIncludeValues: @((options & 1) == 0), + (__bridge NSString *)OGDescriptionAllGraphs: @(graph == nil) + }; + NSString *description = (__bridge NSString *)Graph::description(graph, options_dict); + if (description == nil) { + return; + } + const char *cstring_name = name ?: "graph.ag-gzon"; + + NSData *data = [NSJSONSerialization dataWithJSONObject:description options:0 error:nil]; + NSString *file_path = [NSString stringWithUTF8String:cstring_name]; + if (cstring_name[0] != '/') { + file_path = [NSTemporaryDirectory() stringByAppendingPathComponent:file_path]; + } + NSError *error = nil; + BOOL success = YES; + if ([file_path.pathExtension isEqualToString:@"ag-gzon"]) { + gzFile file = gzopen(file_path.fileSystemRepresentation, "wb"); + if (file != NULL) { + const char *bytes = (const char *)[data bytes]; + NSUInteger remaining = [data length]; + while (remaining != 0) { + int bytes_written = gzwrite(file, bytes, (unsigned int)remaining); + if (bytes_written <= 0) { + success = NO; + break; + } + bytes += bytes_written; + remaining -= bytes_written; + } + gzclose(file); + } + } else { + success = [data writeToFile:file_path options:0 error:&error]; + } + if (success) { + fprintf(stderr, "Wrote graph data to \"%s\".\n", file_path.UTF8String); + } else { + fprintf(stderr, "Unable to write to \"%s\": %s\n", file_path.UTF8String, error.description.UTF8String); + } + } +} + +#endif /* OG_OBJC_FOUNDATION */ diff --git a/Sources/OpenGraph_SPI/Graph/GraphDescription.cpp b/Sources/OpenGraph_SPI/Graph/GraphDescription.cpp new file mode 100644 index 00000000..a3b03e7b --- /dev/null +++ b/Sources/OpenGraph_SPI/Graph/GraphDescription.cpp @@ -0,0 +1,33 @@ +// +// GraphDescription.cpp +// OpenGraph_SPI + +#include "OGGraphDescription.h" +#include "OGGraph.h" +#include "Graph.hpp" +#include "../Util/assert.hpp" + +CFTypeRef OGGraphDescription(OGGraphRef graph, CFDictionaryRef options) { + #if OG_OBJC_FOUNDATION + if (graph == nullptr) { + return OG::Graph::description(nullptr, (__bridge NSDictionary*)options); + } + if (graph->context.isInvalid()) { + OG::precondition_failure("invalidated graph"); + } + return OG::Graph::description(&graph->context.get_graph(), (__bridge NSDictionary*)options); + #endif +} + +void OGGraphArchiveJSON(char const * _Nullable name) { + #if OG_OBJC_FOUNDATION + OG::Graph::write_to_file(nullptr, name, 0); + #endif +} + +void OGGraphArchiveJSON2(char const * _Nullable name, uint8_t options) { + #if OG_OBJC_FOUNDATION + OG::Graph::write_to_file(nullptr, name, options); + #endif +} + diff --git a/Sources/OpenGraph_SPI/Graph/GraphDescription.mm b/Sources/OpenGraph_SPI/Graph/GraphDescription.mm index 505dc2ce..e6f26b87 100644 --- a/Sources/OpenGraph_SPI/Graph/GraphDescription.mm +++ b/Sources/OpenGraph_SPI/Graph/GraphDescription.mm @@ -1,9 +1,6 @@ // // GraphDescription.mm -// -// -// Created by Kyle on 2024/1/21. -// +// OpenGraph_SPI #include "OGGraphDescription.h" #include "OGGraph.h" @@ -11,8 +8,11 @@ #include "../Util/assert.hpp" #if OG_OBJC_FOUNDATION + #include + const CFStringRef OGDescriptionFormat = CFSTR("format"); +const CFStringRef OGDescriptionIncludeValues = CFSTR("include-values"); CFTypeRef OG::Graph::description(const Graph * _Nullable graph, NSDictionary* dic) { // TODO @@ -21,14 +21,4 @@ return NULL; } -CFTypeRef OGGraphDescription(OGGraphRef graph, CFDictionaryRef options) { - if (graph == nullptr) { - return OG::Graph::description(nullptr, (__bridge NSDictionary*)options); - } - if (graph->context.isInvalid()) { - OG::precondition_failure("invalidated graph"); - } - return OG::Graph::description(&graph->context.get_graph(), (__bridge NSDictionary*)options); -} - #endif /* OG_OBJC_FOUNDATION */ diff --git a/Sources/OpenGraph_SPI/Graph/OGGraph.cpp b/Sources/OpenGraph_SPI/Graph/OGGraph.cpp index 3e283367..dde22526 100644 --- a/Sources/OpenGraph_SPI/Graph/OGGraph.cpp +++ b/Sources/OpenGraph_SPI/Graph/OGGraph.cpp @@ -41,10 +41,6 @@ OGGraphRef OGGraphCreateShared(OGGraphRef storage) { return instance; } -void OGGraphArchiveJSON(char const * _Nullable name) { - OG::Graph::write_to_file(nullptr, name); -} - namespace { CFRuntimeClass &graph_type_id() { static auto dealloc = [](const void* ptr) { diff --git a/Sources/OpenGraph_SPI/include/OGDebugServer.h b/Sources/OpenGraph_SPI/include/OGDebugServer.h index 28fb3f70..6cc209a7 100644 --- a/Sources/OpenGraph_SPI/include/OGDebugServer.h +++ b/Sources/OpenGraph_SPI/include/OGDebugServer.h @@ -20,14 +20,19 @@ typedef const OGDebugServerStorage *OGDebugServer OG_SWIFT_STRUCT; // MARK: - Exported C functions OG_EXTERN_C_BEGIN + OG_EXPORT OGDebugServer _Nullable OGDebugServerStart(unsigned int mode) OG_SWIFT_NAME(OGDebugServer.start(mode:)); + OG_EXPORT void OGDebugServerStop(void) OG_SWIFT_NAME(OGDebugServer.stop()); + OG_EXPORT CFURLRef _Nullable OGDebugServerCopyURL(void) OG_SWIFT_NAME(OGDebugServer.copyURL()); + OG_EXPORT void OGDebugServerRun(int timeout) OG_SWIFT_NAME(OGDebugServer.run(timeout:)); + OG_EXTERN_C_END OG_IMPLICIT_BRIDGING_DISABLED diff --git a/Sources/OpenGraph_SPI/include/OGGraph.h b/Sources/OpenGraph_SPI/include/OGGraph.h index fd59f936..49c67a72 100644 --- a/Sources/OpenGraph_SPI/include/OGGraph.h +++ b/Sources/OpenGraph_SPI/include/OGGraph.h @@ -37,14 +37,6 @@ OG_EXPORT OG_REFINED_FOR_SWIFT OGGraphRef OGGraphCreateShared(_Nullable OGGraphRef graph) OG_SWIFT_NAME(OGGraphRef.init(shared:)); -OG_EXPORT -OG_REFINED_FOR_SWIFT -void OGGraphArchiveJSON(char const * _Nullable name) OG_SWIFT_NAME(OGGraphRef.archiveJSON(name:)); - -OG_EXPORT -OG_REFINED_FOR_SWIFT -_Nullable CFTypeRef OGGraphDescription(_Nullable OGGraphRef graph, CFDictionaryRef options) OG_SWIFT_NAME(OGGraphRef.description(_:options:)); - OG_EXPORT OG_REFINED_FOR_SWIFT CFTypeID OGGraphGetTypeID(void) OG_SWIFT_NAME(getter:OGGraphRef.typeID()); diff --git a/Sources/OpenGraph_SPI/include/OGGraphDescription.h b/Sources/OpenGraph_SPI/include/OGGraphDescription.h index d38f1e2e..b755d784 100644 --- a/Sources/OpenGraph_SPI/include/OGGraphDescription.h +++ b/Sources/OpenGraph_SPI/include/OGGraphDescription.h @@ -6,6 +6,7 @@ #define OGGraphDescription_h #include "OGBase.h" +#include "OGGraph.h" OG_ASSUME_NONNULL_BEGIN @@ -18,8 +19,29 @@ OG_EXTERN_C_BEGIN OG_EXPORT const CFStringRef OGDescriptionFormat OG_SWIFT_NAME(OGGraphRef.descriptionFormat); +OG_EXPORT +const CFStringRef OGDescriptionIncludeValues OG_SWIFT_NAME(OGGraphRef.descriptionIncludeValues); + +static const CFStringRef OGDescriptionFormatDot OG_SWIFT_NAME(OGGraphRef.descriptionFormatDot) = CFSTR("graph/dot"); + +static const CFStringRef OGDescriptionFormatDictionary OG_SWIFT_NAME(OGGraphRef.descriptionFormatDictionary) = CFSTR("graph/dict"); + +static const CFStringRef OGDescriptionAllGraphs OG_SWIFT_NAME(OGGraphRef.descriptionAllGraphs) = CFSTR("all_graphs"); + #endif +OG_EXPORT +OG_REFINED_FOR_SWIFT +void OGGraphArchiveJSON(char const * _Nullable name) OG_SWIFT_NAME(OGGraphRef.archiveJSON(name:)); + +OG_EXPORT +OG_REFINED_FOR_SWIFT +void OGGraphArchiveJSON2(char const * _Nullable name, uint8_t options) OG_SWIFT_NAME(OGGraphRef.archiveJSON(name:options:)); + +OG_EXPORT +OG_REFINED_FOR_SWIFT +_Nullable CFTypeRef OGGraphDescription(_Nullable OGGraphRef graph, CFDictionaryRef options) OG_SWIFT_NAME(OGGraphRef.description(_:options:)); + OG_EXTERN_C_END OG_IMPLICIT_BRIDGING_DISABLED diff --git a/Sources/OpenGraph_SPI/include/OpenGraph.h b/Sources/OpenGraph_SPI/include/OpenGraph.h index 20036e5f..046aabc1 100644 --- a/Sources/OpenGraph_SPI/include/OpenGraph.h +++ b/Sources/OpenGraph_SPI/include/OpenGraph.h @@ -11,6 +11,7 @@ #include "OGDebugServer.h" #include "OGGraph.h" #include "OGGraphContext.h" +#include "OGGraphDescription.h" #include "OGGraphTracing.h" #include "OGInputOptions.h" #include "OGSearchOptions.h" diff --git a/Tests/OpenGraphCompatibilityTests/Graph/GraphTests.swift b/Tests/OpenGraphCompatibilityTests/Graph/GraphTests.swift index 8d20efee..cdf8b6c4 100644 --- a/Tests/OpenGraphCompatibilityTests/Graph/GraphTests.swift +++ b/Tests/OpenGraphCompatibilityTests/Graph/GraphTests.swift @@ -40,7 +40,12 @@ struct GraphTests { @Test(.disabled(if: !compatibilityTestEnabled, "Not implemented on OG")) func graphDescriptionDict() throws { - let description = try #require(Graph.description(nil, options: ["format": "graph/dict"] as NSDictionary)) + let description = try #require(Graph.description( + nil, + options: [ + Graph.descriptionFormat: Graph.descriptionFormatDictionary + ] as NSDictionary + )) let dic = description as! Dictionary #expect(dic["version"] as? UInt32 == 2) #expect((dic["graphs"] as? NSArray)?.count == 0) @@ -49,7 +54,7 @@ struct GraphTests { @Test(.disabled(if: !compatibilityTestEnabled, "Not implemented on OG")) func graphDescriptionDot() throws { let options = NSMutableDictionary() - options["format"] = "graph/dot" + options[Graph.descriptionFormat] = Graph.descriptionFormatDot #expect(Graph.description(nil, options: options) == nil) let graph = Graph() let description = try #require(Graph.description(graph, options: options))