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
167
168
169
170
171
172
173
174
175
176
177
// SPDX-License-Identifier: MIT
// Copyright 2026 Tom F. <https://github.com/tomtom215/>
// My way of giving something small back to the open source community
// and encouraging more Rust development!
//! Type aliases for the five required `DuckDB` aggregate callback signatures.
//!
//! Import these type aliases when defining your callback functions to ensure
//! you use the correct signature. A mismatch in any parameter type is a silent
//! bug that is extremely difficult to debug.
//!
//! # The five required callbacks
//!
//! Every `DuckDB` aggregate function requires exactly these five callbacks
//! (plus an optional `Destructor`):
//!
//! | Callback | When called | Purpose |
//! |----------|-------------|---------|
//! | [`StateSizeFn`] | Once at registration | Returns `sizeof(FfiState)` in bytes |
//! | [`StateInitFn`] | Per state allocation | Initializes a fresh state |
//! | [`UpdateFn`] | Per batch of rows | Accumulates data from a chunk into the state |
//! | [`CombineFn`] | Parallel merge | Merges source state into target state |
//! | [`FinalizeFn`] | Once at the end | Writes results from states to output vector |
//! | [`DestroyFn`] | After finalize | Frees per-state memory |
//!
//! # Important: Array-of-pointers calling convention
//!
//! The `update`, `combine`, and `finalize` callbacks receive
//! `*mut duckdb_aggregate_state` — a pointer to an **array** of state pointers.
//!
//! # Pitfall: COMBINE must propagate ALL config fields
//!
//! See the crate-level documentation for a worked example of this critical bug.
//!
//! # Example
//!
//! ```rust
//! use quack_rs::aggregate::callbacks::{StateSizeFn, StateInitFn, UpdateFn, CombineFn, FinalizeFn, DestroyFn};
//! use libduckdb_sys::{duckdb_function_info, duckdb_aggregate_state, duckdb_data_chunk, duckdb_vector, idx_t};
//!
//! unsafe extern "C" fn my_state_size(_: duckdb_function_info) -> idx_t { 8 }
//! unsafe extern "C" fn my_init(_: duckdb_function_info, _: duckdb_aggregate_state) {}
//! unsafe extern "C" fn my_update(_: duckdb_function_info, _: duckdb_data_chunk, _: *mut duckdb_aggregate_state) {}
//! unsafe extern "C" fn my_combine(_: duckdb_function_info, _: *mut duckdb_aggregate_state, _: *mut duckdb_aggregate_state, _: idx_t) {}
//! unsafe extern "C" fn my_finalize(_: duckdb_function_info, _: *mut duckdb_aggregate_state, _: duckdb_vector, _: idx_t, _: idx_t) {}
//! unsafe extern "C" fn my_destroy(_: *mut duckdb_aggregate_state, _: idx_t) {}
//!
//! let _: StateSizeFn = my_state_size;
//! let _: StateInitFn = my_init;
//! let _: UpdateFn = my_update;
//! let _: CombineFn = my_combine;
//! let _: FinalizeFn = my_finalize;
//! let _: DestroyFn = my_destroy;
//! ```
use ;
/// Returns the size of the aggregate state struct in bytes.
///
/// # Example
///
/// ```rust
/// use quack_rs::aggregate::callbacks::StateSizeFn;
/// use libduckdb_sys::{duckdb_function_info, idx_t};
///
/// unsafe extern "C" fn state_size(_: duckdb_function_info) -> idx_t {
/// std::mem::size_of::<u64>() as idx_t
/// }
/// let _: StateSizeFn = state_size;
/// ```
pub type StateSizeFn = unsafe extern "C" fn ;
/// Initializes a freshly allocated aggregate state.
///
/// The `state` parameter is a single `duckdb_aggregate_state` for this group.
///
/// # Example
///
/// ```rust
/// use quack_rs::aggregate::callbacks::StateInitFn;
/// use libduckdb_sys::{duckdb_function_info, duckdb_aggregate_state};
///
/// unsafe extern "C" fn state_init(_: duckdb_function_info, _state: duckdb_aggregate_state) {}
/// let _: StateInitFn = state_init;
/// ```
pub type StateInitFn =
unsafe extern "C" fn;
/// Accumulates data from a chunk into the aggregate states.
///
/// `states` is a pointer to an array of state pointers — one per group.
pub type UpdateFn = unsafe extern "C" fn;
/// Merges source states into target states.
///
/// Both `source` and `target` point to arrays of `count` state pointers.
///
/// # Pitfall L1: Combine must propagate ALL config fields
///
/// The `target` states are freshly zero-initialized. All configuration fields
/// must be copied from `source`, not just accumulated data values.
pub type CombineFn = unsafe extern "C" fn;
/// Writes final results from aggregate states to the output vector.
///
/// `source` points to an array of `count` state pointers.
/// Write `count` results starting at `offset` in the output vector.
///
/// # NULL output — Pitfall L4
///
/// Call `duckdb_vector_ensure_validity_writable` before `duckdb_vector_get_validity`
/// when writing NULL values, or use [`VectorWriter::set_null`][crate::vector::VectorWriter::set_null].
pub type FinalizeFn = unsafe extern "C" fn;
/// Frees memory allocated by [`StateInitFn`].
///
/// Called after finalize. Must free all heap allocations made in `StateInitFn`.
pub type DestroyFn = unsafe extern "C" fn;