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
// Copyright 2026 Colliery, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! FNV-1a interface hashing for compile-time ABI drift detection.
//!
//! The proc macro computes an `interface_hash` from the sorted required method
//! signatures of a trait. The host checks this hash at load time to reject
//! plugins compiled against a different interface.
/// FNV-1a 64-bit offset basis.
const FNV_OFFSET_BASIS: u64 = 0xcbf29ce484222325;
/// FNV-1a 64-bit prime.
const FNV_PRIME: u64 = 0x100000001b3;
/// Compute the FNV-1a 64-bit hash of a byte slice.
pub const
/// Compute the interface hash from a set of method signatures.
///
/// Signatures are sorted lexicographically before hashing to ensure
/// order-independence. Each signature is joined with `\n` as a separator.
///
/// This function is **not** `const` because it allocates for sorting.
/// The proc macro calls this at compile time via a build-script-like pattern,
/// or uses `fnv1a` directly on pre-sorted, concatenated signatures.
/// Build the canonical signature string for one method.
///
/// Format: `"{name}:{arg_type_1},{arg_type_2}->{return_type}{!raw?}"`.
///
/// - `arg_types` are pre-stringified (typically by `syn::Type` →
/// `to_token_stream().to_string()` — the proc macro and any other
/// tooling that wants to compute the same hash must use the same
/// formatter).
/// - `return_type` is the stringified return type, or empty string for
/// methods returning `()`.
/// - `wire_raw = true` appends a trailing `!raw` marker so methods opted
/// into raw wire mode hash differently from bincode-typed methods of
/// the same Rust signature. This is the protection that makes a
/// wire-mode mismatch surface as a load-time hash mismatch instead of
/// silent data corruption.
/// - `streaming = true` appends a trailing `!stream` marker (after any
/// `!raw`) so a server-streaming method (`-> fidius::Stream<T>`, where
/// `ret` is the per-item type `T`) hashes differently from a unary
/// `-> T` method of the same name/args. Same protection as `!raw`, for
/// the streaming/unary split (FIDIUS-I-0026, D4).
///
/// This function lives in `fidius-core` (not `fidius-macro`) so the proc
/// macro and downstream tooling like `fidius python-stub` share a single
/// source of truth for the format. Drift between them = silent hash
/// mismatch, which is exactly what the load-time check is meant to catch
/// — but better to never have the drift in the first place.