nandi/frqpublic Fork 0
7751d4ffae3c665d7bccb4e9ba0896939d2fafee
Commits
Clone
git clone https://git.rickub.com/nandi/frq.git
git clone ssh://git@rickub.com/nandi/frq.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

py2jolt.py · 106 lines · 4.0 KBPython Blame HistoryRaw
Bind libmoq_ffi from the object's own metadata, not from its header 9f081a1 nandi 9d ago1#!/usr/bin/env python3
2"""Turn uniffi-bindgen's Python output into jolt `defcfn` declarations.
3
4The Python backend emits, for every entry point in the library, a pair of
5lines that together are an exact ABI description:
6
7 _UniffiLib.uniffi_moq_ffi_fn_method_moqclient_connect.argtypes = (
8 ctypes.c_uint64, _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus),
9 )
10 _UniffiLib.uniffi_moq_ffi_fn_method_moqclient_connect.restype = ctypes.c_uint64
11
12That is generated from the metadata embedded in the .so itself, so it matches
13the object being bound rather than a header shipped alongside it -- which for
14this release is a different build (the Apple artifact carries audio/ video, the
15Linux and Android ones do not).
16"""
17import re, sys, collections
18
19CTYPE = {
20 "ctypes.c_int8": ":int8", "ctypes.c_uint8": ":uint8",
21 "ctypes.c_int16": ":int16", "ctypes.c_uint16": ":uint16",
22 "ctypes.c_int32": ":int32", "ctypes.c_uint32": ":uint32",
23 "ctypes.c_int64": ":int64", "ctypes.c_uint64": ":uint64",
24 "ctypes.c_float": ":float", "ctypes.c_double": ":double",
25 "ctypes.c_void_p": ":pointer", "ctypes.c_size_t": ":uint64",
26 "None": ":void",
27}
28# A RustBuffer crosses by value; a status is always a pointer out-param.
29RB = "[:by-value [:struct [[:capacity :uint64] [:len :uint64] [:data :pointer]]]]"
30STATUS = ":pointer"
31
32def conv(t):
33 t = t.strip().rstrip(",").strip()
34 if not t:
35 return None
36 if t in CTYPE:
37 return CTYPE[t]
38 if "RustCallStatus" in t:
39 return STATUS
40 if "RustBuffer" in t:
41 return RB
42 if "ForeignBytes" in t:
43 return "[:by-value [:struct [[:len :int32] [:data :pointer]]]]"
44 if t.startswith("ctypes.POINTER"):
45 return ":pointer"
46 # A function-pointer typedef (the future continuation) -- jolt lowers an
47 # ffi/callback to a plain pointer, so that is what the slot takes.
48 if "callback" in t.lower() or "struct" in t.lower():
49 return ":pointer"
50 return None # unknown -- reported, never guessed
51
52def split_args(s):
53 out, depth, cur = [], 0, ""
54 for ch in s:
55 if ch == "(":
56 depth += 1
57 elif ch == ")":
58 depth -= 1
59 if ch == "," and depth == 0:
60 out.append(cur); cur = ""
61 else:
62 cur += ch
63 if cur.strip():
64 out.append(cur)
65 return out
66
67def main(path):
68 src = open(path).read()
69 args = dict(re.findall(r"_UniffiLib\.(\w+)\.argtypes\s*=\s*\(([^)]*(?:\([^)]*\)[^)]*)*)\)", src))
70 rets = dict(re.findall(r"_UniffiLib\.(\w+)\.restype\s*=\s*(.+)", src))
71 names = sorted(set(args) | set(rets))
72 unknown = collections.Counter()
73 rows = []
74 for n in names:
75 a = [conv(x) for x in split_args(args.get(n, ""))]
76 r = conv(rets.get(n, "None"))
77 if None in a or r is None:
78 for x in split_args(args.get(n, "")) + [rets.get(n, "None")]:
79 if conv(x) is None:
80 unknown[x.strip()] += 1
81 continue
82 rows.append((n, a, r))
83 return rows, unknown, len(names)
84
85if __name__ == "__main__":
86 rows, unknown, total = main(sys.argv[1])
87 print(f";; {len(rows)} of {total} entry points bound", file=sys.stderr)
88 if unknown:
89 print(";; UNMAPPED (left unbound rather than guessed):", file=sys.stderr)
90 for t, c in unknown.most_common():
91 print(f";; {t} x{c}", file=sys.stderr)
92 for n, a, r in rows:
93 # Anchored, longest-first: "uniffi_moq_ffi_checksum_" must not be
94 # eaten by the "ffi_moq_ffi_" that also matches inside it.
95 for pre in ("uniffi_moq_ffi_fn_", "uniffi_moq_ffi_checksum_",
96 "ffi_moq_ffi_", "uniffi_moq_ffi_"):
97 if n.startswith(pre):
98 stem = n[len(pre):]
99 if pre.endswith("checksum_"):
100 stem = "checksum-" + stem
101 break
102 else:
103 stem = n
104 jolt_name = stem.replace("_", "-")
105 argv = " ".join(a) if a else ""
106 print(f'(ffi/defcfn {jolt_name} "{n}" [{argv}] {r})')