@@ -14,7 +14,8 @@ struct NxFunctionView<Root: RootRegistry>: View {
14
14
@LiveAttribute ( " bytecode " ) private var bytecode : String ? = nil
15
15
@LiveAttribute ( " signature " ) private var signature : String ? = nil
16
16
@LiveAttribute ( " device " ) private var deviceURI : String ? = nil
17
- @LiveAttribute ( " trigger " ) private var trigger : Bool = false
17
+ @LiveAttribute ( " inputs " ) private var serializedInputs : [ String ] ? = nil
18
+ @LiveAttribute ( " num-outputs " ) private var numOutputs : Int ? = nil
18
19
@Event ( " on-execution " , type: " change " ) private var change
19
20
20
21
var body : some View {
@@ -32,18 +33,125 @@ struct NxFunctionView<Root: RootRegistry>: View {
32
33
}
33
34
}
34
35
35
- private func run( ) {
36
- if bytecode == nil {
37
- return
36
+ private func convertBase64StringToBytecode( _ base64String: String ) -> ( bytecodeSize: UInt64 , bytecodePointer: UnsafePointer < CUnsignedChar > ? ) ? {
37
+ // Step 1: Decode the Base64 string into Data
38
+ guard let decodedData = Data ( base64Encoded: base64String) else {
39
+ print ( " Failed to decode base64 string. " )
40
+ return nil
41
+ }
42
+
43
+ // Step 2: Get the size of the data
44
+ let bytecodeSize = UInt64 ( decodedData. count)
45
+
46
+ // Step 3: Convert Data to UnsafePointer<CUnsignedChar>
47
+ // We use `withUnsafeBytes` to get a pointer to the data
48
+ let bytecodePointer = decodedData. withUnsafeBytes { ( pointer: UnsafeRawBufferPointer ) -> UnsafePointer < CUnsignedChar > ? in
49
+ return pointer. bindMemory ( to: CUnsignedChar . self) . baseAddress
50
+ }
51
+
52
+ return ( bytecodeSize, bytecodePointer)
53
+ }
54
+
55
+ private func convertToCStringArray( from strings: [ String ] ) -> UnsafePointer < UnsafePointer < CChar > > ? {
56
+ // Array to hold the C strings (UnsafePointer<CChar>)
57
+ var cStrings : [ UnsafePointer < CChar > ] = [ ]
58
+
59
+ for string in strings {
60
+ // Decode the base64 string to Data
61
+ guard let decodedData = Data ( base64Encoded: string) else {
62
+ print ( " Failed to decode base64 string: \( string) " )
63
+ return nil
64
+ }
65
+
66
+ // Convert Data to a C string (null-terminated UTF-8)
67
+ let cString = decodedData. withUnsafeBytes { ( pointer: UnsafeRawBufferPointer ) -> UnsafePointer < CChar > ? in
68
+ guard let baseAddress = pointer. baseAddress else { return nil }
69
+ // Allocate memory for the C string and copy the data
70
+ let cStringPointer = UnsafeMutablePointer< CChar> . allocate( capacity: decodedData. count + 1 )
71
+ cStringPointer. initialize ( from: baseAddress. assumingMemoryBound ( to: CChar . self) , count: decodedData. count)
72
+ cStringPointer [ decodedData. count] = 0 // Null-terminate the string
73
+ return UnsafePointer ( cStringPointer)
74
+ }
75
+
76
+ guard let cStr = cString else {
77
+ print ( " Failed to convert Data to C string. " )
78
+ return nil
79
+ }
80
+
81
+ cStrings. append ( cStr)
38
82
}
39
83
40
- if let vmInstance = globalVmInstance,
41
- let driverRegistry = globalDriverRegistry {
42
- print ( " Executing function \( signature ?? " None " ) on device: \( deviceURI ?? " None " ) " )
43
- change ( value: " Sending something back " )
84
+ // Allocate memory for the array of C strings
85
+ let cStringsPointer = UnsafeMutablePointer< UnsafePointer< CChar>>. allocate( capacity: cStrings. count)
86
+
87
+ // Copy the C strings to the allocated array
88
+ cStringsPointer. initialize ( from: & cStrings, count: cStrings. count)
89
+
90
+ // Return the pointer to the array
91
+ return UnsafePointer ( cStringsPointer)
92
+ }
93
+
94
+ private func base64EncodedStrings( from serializedOutputs: UnsafePointer < UnsafePointer < CChar > > , count: Int ) -> [ String ] {
95
+ // Convert UnsafePointer to a Swift array of UnsafePointer<CChar>
96
+ let cStringPointers = Array ( UnsafeBufferPointer ( start: serializedOutputs, count: count) )
97
+
98
+ var base64Strings : [ String ] = [ ]
99
+
100
+ for cStringPointer in cStringPointers {
101
+ // Convert each C string to a Swift String
102
+ let string = String ( cString: cStringPointer)
103
+
104
+ // Encode the string to Base64
105
+ if let data = string. data ( using: . utf8) {
106
+ let base64String = data. base64EncodedString ( )
107
+ base64Strings. append ( base64String)
108
+ }
109
+ }
110
+
111
+ return base64Strings
112
+ }
113
+
114
+
115
+ private func run( ) {
116
+ if bytecode != nil ,
117
+ deviceURI != nil ,
118
+ globalVmInstance != nil ,
119
+ globalDriverRegistry != nil ,
120
+ serializedInputs != nil ,
121
+ let ( bytecodeSize, bytecodePointer) = convertBase64StringToBytecode ( bytecode!) ,
122
+ let inputs = convertToCStringArray ( from: serializedInputs!) {
123
+ let deviceURIcstr = strdup ( deviceURI!)
124
+ let device = nx_iree_create_device ( globalDriverRegistry!, UnsafePointer ( deviceURIcstr) !)
125
+ deviceURIcstr? . deallocate ( )
126
+
127
+ let serializedOutputs : UnsafePointer < UnsafePointer < CChar > > ? = nil
128
+ let errorMessage = UnsafeMutablePointer< CChar> . allocate( capacity: 256 )
129
+
130
+ print ( " Executing function \( signature ?? " None " ) on device: \( deviceURI ?? " None " ) " )
131
+
132
+ let result = nx_iree_call (
133
+ globalVmInstance!,
134
+ device,
135
+ bytecodeSize,
136
+ bytecodePointer!,
137
+ UInt64 ( serializedInputs!. count) ,
138
+ inputs,
139
+ UInt64 ( numOutputs!) ,
140
+ serializedOutputs!,
141
+ errorMessage)
142
+
143
+ if result != 0 {
144
+ print ( errorMessage)
145
+ return
146
+ }
147
+
148
+ for i in 0 ..< serializedInputs!. count {
149
+ inputs [ i] . deallocate ( )
150
+ }
151
+ inputs. deallocate ( )
152
+
153
+ change ( value: base64EncodedStrings ( from: serializedOutputs!, count: numOutputs!) )
44
154
} else {
45
- print ( " vm instance: \( globalVmInstance) " )
46
- print ( " driver registry: \( globalDriverRegistry) " )
47
155
print ( " IREE components are not initialized. " )
48
156
}
49
157
}
0 commit comments