-
Notifications
You must be signed in to change notification settings - Fork 99
Expand file tree
/
Copy pathFFMSwift2JavaGenerator+FoundationData.swift
More file actions
166 lines (154 loc) · 6.17 KB
/
FFMSwift2JavaGenerator+FoundationData.swift
File metadata and controls
166 lines (154 loc) · 6.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2026 Apple Inc. and the Swift.org project authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See CONTRIBUTORS.txt for the list of Swift.org project authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import CodePrinting
import SwiftJavaConfigurationShared
import SwiftJavaJNICore
import SwiftSyntax
import SwiftSyntaxBuilder
import struct Foundation.URL
extension FFMSwift2JavaGenerator {
/// Print Java helper methods for Foundation.Data type
package func printFoundationDataHelpers(_ printer: inout CodePrinter, _ decl: ImportedNominalType) {
let typeName = decl.swiftNominal.name
let thunkNameCopyBytes = "swiftjava_\(swiftModuleName)_\(typeName)_copyBytes__"
printer.printSeparator("\(typeName) helper methods")
// This is primarily here for API parity with the JNI version and easier discovery
printer.print(
"""
/**
* Creates a new Swift {@link \(typeName)} instance from a byte array.
*
* @param bytes The byte array to copy into the \(typeName)
* @param arena The arena for memory management
* @return A new \(typeName) instance containing a copy of the bytes
*/
public static \(typeName) fromByteArray(byte[] bytes, AllocatingSwiftArena arena) {
Objects.requireNonNull(bytes, "bytes cannot be null");
return \(typeName).init(bytes, arena);
}
"""
)
// TODO: Implement a fromByteBuffer as well
// Print the descriptor class for copyBytes native call using the shared helper
let copyBytesCFunc = CFunction(
resultType: .void,
name: thunkNameCopyBytes,
parameters: [
CParameter(name: "self", type: .qualified(const: true, volatile: false, type: .pointer(.void))),
CParameter(name: "destination", type: .pointer(.void)),
CParameter(name: "count", type: .integral(.ptrdiff_t)),
],
isVariadic: false
)
printJavaBindingDescriptorClass(&printer, copyBytesCFunc)
printer.print(
"""
/**
* Copies the contents of this \(typeName) to a new {@link MemorySegment}.
*
* This is the most efficient way to access \(typeName) bytes from Java when you don't
* need a {@code byte[]}. The returned segment is valid for the lifetime of the arena.
*
* <p>Copy count: 1 (Swift Data -> MemorySegment)
*
* @param arena The arena to allocate the segment in
* @return A MemorySegment containing a copy of this \(typeName)'s bytes
*/
public MemorySegment toMemorySegment(AllocatingSwiftArena arena) {
$ensureAlive();
long count = getCount();
if (count == 0) return MemorySegment.NULL;
MemorySegment segment = arena.allocate(count);
\(thunkNameCopyBytes).call(this.$memorySegment(), segment, count);
return segment;
}
"""
)
printer.print(
"""
/**
* Copies the contents of this \(typeName) to a new {@link ByteBuffer}.
*
* The returned {@link java.nio.ByteBuffer} is a view over native memory and is valid for the
* lifetime of the arena. This avoids an additional copy to the Java heap.
*
* <p>Copy count: 1 (Swift Data -> native memory (managed by passed arena), then zero-copy view)
*
* @param arena The arena to allocate the underlying memory in
* @return A ByteBuffer view of the copied bytes
*/
public java.nio.ByteBuffer toByteBuffer(AllocatingSwiftArena arena) {
$ensureAlive();
long count = getCount();
if (count == 0) return java.nio.ByteBuffer.allocate(0);
MemorySegment segment = arena.allocate(count);
\(thunkNameCopyBytes).call(this.$memorySegment(), segment, count);
return segment.asByteBuffer();
}
"""
)
printer.print(
"""
/**
* Copies the contents of this \(typeName) to a new byte array.
* The lifetime of the array is independent of the arena, the arena is just used for an intermediary copy.
*
* <p>Copy count: 2 (Swift Data -> MemorySegment -> byte[])
*
* <p>For better performance when you can work with {@link MemorySegment} or
* {@link java.nio.ByteBuffer}, prefer {@link #toMemorySegment} or {@link #toByteBuffer}.
*
* @param arena The arena to use for temporary native memory allocation
* @return A byte array containing a copy of this \(typeName)'s bytes
*/
public byte[] toByteArray(AllocatingSwiftArena arena) {
$ensureAlive();
long count = getCount();
if (count == 0) return new byte[0];
MemorySegment segment = arena.allocate(count);
\(thunkNameCopyBytes).call(this.$memorySegment(), segment, count);
return segment.toArray(ValueLayout.JAVA_BYTE);
}
"""
)
printer.print(
"""
/**
* Copies the contents of this \(typeName) to a new byte array.
* The lifetime of the array is independent of the arena, the arena is just used for an intermediary copy.
*
* This is a convenience method that creates a temporary arena for the copy.
* For repeated calls, prefer {@link #toByteArray(AllocatingSwiftArena)} to reuse an arena.
*
* <p>Copy count: 2 (Swift Data -> MemorySegment -> byte[])
*
* <p>For better performance when you can work with {@link MemorySegment} or
* {@link java.nio.ByteBuffer}, prefer {@link #toMemorySegment} or {@link #toByteBuffer}.
*
* @return A byte array containing a copy of this \(typeName)'s bytes
*/
public byte[] toByteArray() {
$ensureAlive();
long count = getCount();
if (count == 0) return new byte[0];
try (var arena = Arena.ofConfined()) {
MemorySegment segment = arena.allocate(count);
\(thunkNameCopyBytes).call(this.$memorySegment(), segment, count);
return segment.toArray(ValueLayout.JAVA_BYTE);
}
}
"""
)
}
}