-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathNativeCall.java
More file actions
89 lines (78 loc) · 3.14 KB
/
Copy pathNativeCall.java
File metadata and controls
89 lines (78 loc) · 3.14 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
package io.github.dfa1.zstd;
import java.lang.foreign.MemorySegment;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
/// Package-private helpers that adapt raw FFM downcalls to the zstd error
/// convention: run a native call, decode a zstd `size_t` error code into a
/// {@link ZstdException}, and guard native-segment arguments. Shared by the
/// binding classes so the conventions live in one place.
final class NativeCall {
/// A native call returning a zstd `size_t` status that may encode an error.
@FunctionalInterface
interface ZstdCall {
long run() throws Throwable;
}
/// Invokes a size-returning zstd call and converts a zstd error code into a
/// {@link ZstdException}.
static long checkReturnValue(ZstdCall c) {
long code;
try {
code = c.run();
} catch (Throwable t) {
throw rethrow(t);
}
if (isError(code)) {
throw new ZstdException(errorName(code), ZstdErrorCode.of(errorCode(code)));
}
return code;
}
static boolean isError(long code) {
try {
return ((int) Bindings.IS_ERROR.invokeExact(code)) != 0;
} catch (Throwable t) {
throw rethrow(t);
}
}
private static int errorCode(long code) {
try {
return (int) Bindings.GET_ERROR_CODE.invokeExact(code);
} catch (Throwable t) {
throw rethrow(t);
}
}
@SuppressWarnings("restricted") // reinterpret needed to read a C string of unknown length
private static String errorName(long code) {
try {
MemorySegment p = (MemorySegment) Bindings.GET_ERROR_NAME.invokeExact(code);
return p.reinterpret(Long.MAX_VALUE).getString(0, StandardCharsets.US_ASCII);
} catch (Throwable t) {
throw rethrow(t);
}
}
/// Whether `seg` denotes "no segment": either a Java `null` reference or the
/// [MemorySegment#NULL] zero-address sentinel. Both map to a null pointer in C,
/// which the dictionary entry points read as "clear".
static boolean isNull(MemorySegment seg) {
return seg == null || MemorySegment.NULL.equals(seg);
}
/// Guards a zero-copy entry point: the segment handed to zstd must be backed
/// by native (off-heap) memory, since its address is dereferenced in C. Fails
/// fast with a clear message instead of the FFM linker's cryptic error.
static void requireNative(MemorySegment seg, String name) {
Objects.requireNonNull(seg, name);
if (!seg.isNative()) {
throw new IllegalArgumentException(
name + " must be a native (off-heap) MemorySegment; got a heap segment");
}
}
/// Rethrows any `Throwable` as if unchecked, laundering the checked
/// `Throwable` that {@link java.lang.invoke.MethodHandle#invokeExact} declares.
/// The shared sink for every binding class's native-call catch blocks.
@SuppressWarnings("unchecked")
static <E extends Throwable> RuntimeException rethrow(Throwable t) throws E {
throw (E) t;
}
private NativeCall() {
// no instances
}
}