Skip to content

Commit f5fd945

Browse files
committed
feat: Add zrtl runtime crate for ZRTL plugin development
New sdk/zrtl crate providing Rust types for ZRTL plugins: - ZrtlString: Length-prefixed string with UTF-8 support - ZrtlArray<T>: Capacity+length array with push/pop/get - DynamicBox: Type-erased value container with TypeMeta - GenericBox: Generic value wrapper for polymorphic code - TypeSystem: TypeId, TypeCategory, TypeTag, TypeMeta types - Plugin infrastructure: ZrtlSymbol, ZrtlSymbolEntry, ZrtlInfo C test harness (sdk/tests/test_zrtl.c): - Tests for zrtl.h macros and inline functions - Array and string iterator tests - UTF-8 codepoint iteration tests
1 parent 49cd27d commit f5fd945

9 files changed

Lines changed: 2832 additions & 0 deletions

File tree

sdk/tests/test_zrtl.c

Lines changed: 361 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,361 @@
1+
/*
2+
* ZRTL SDK Test Suite
3+
*
4+
* Demonstrates and tests the ZRTL SDK functionality including:
5+
* - String operations (canonical format)
6+
* - Array operations (canonical format)
7+
* - Iterator protocol
8+
* - Test harness macros
9+
*
10+
* Build and run:
11+
* cd sdk/tests
12+
* gcc -o test_zrtl test_zrtl.c && ./test_zrtl
13+
*/
14+
15+
#include "../zrtl.h"
16+
17+
/* Initialize test state before test functions */
18+
ZRTL_TEST_INIT();
19+
20+
/* ============================================================
21+
* String Tests
22+
* ============================================================ */
23+
24+
ZRTL_TEST(test_string_create) {
25+
ZrtlStringPtr str = zrtl_string_new("Hello");
26+
ZRTL_ASSERT_NOT_NULL(str);
27+
ZRTL_ASSERT_EQ(ZRTL_STRING_LENGTH(str), 5);
28+
29+
/* Verify actual bytes */
30+
const char* data = ZRTL_STRING_DATA(str);
31+
ZRTL_ASSERT_EQ(data[0], 'H');
32+
ZRTL_ASSERT_EQ(data[1], 'e');
33+
ZRTL_ASSERT_EQ(data[2], 'l');
34+
ZRTL_ASSERT_EQ(data[3], 'l');
35+
ZRTL_ASSERT_EQ(data[4], 'o');
36+
37+
zrtl_string_free(str);
38+
ZRTL_PASS();
39+
}
40+
41+
ZRTL_TEST(test_string_empty) {
42+
ZrtlStringPtr str = zrtl_string_empty();
43+
ZRTL_ASSERT_NOT_NULL(str);
44+
ZRTL_ASSERT_EQ(ZRTL_STRING_LENGTH(str), 0);
45+
46+
zrtl_string_free(str);
47+
ZRTL_PASS();
48+
}
49+
50+
ZRTL_TEST(test_string_from_bytes) {
51+
const char bytes[] = { 'A', 'B', 'C' };
52+
ZrtlStringPtr str = zrtl_string_from_bytes(bytes, 3);
53+
ZRTL_ASSERT_NOT_NULL(str);
54+
ZRTL_ASSERT_EQ(ZRTL_STRING_LENGTH(str), 3);
55+
56+
const char* data = ZRTL_STRING_DATA(str);
57+
ZRTL_ASSERT_EQ(data[0], 'A');
58+
ZRTL_ASSERT_EQ(data[1], 'B');
59+
ZRTL_ASSERT_EQ(data[2], 'C');
60+
61+
zrtl_string_free(str);
62+
ZRTL_PASS();
63+
}
64+
65+
ZRTL_TEST(test_string_copy) {
66+
ZrtlStringPtr original = zrtl_string_new("Test");
67+
ZRTL_ASSERT_NOT_NULL(original);
68+
69+
ZrtlStringPtr copy = zrtl_string_copy(original);
70+
ZRTL_ASSERT_NOT_NULL(copy);
71+
ZRTL_ASSERT_NE(original, copy); /* Different pointers */
72+
ZRTL_ASSERT_EQ(ZRTL_STRING_LENGTH(copy), ZRTL_STRING_LENGTH(original));
73+
74+
/* Contents should be equal */
75+
ZRTL_ASSERT(zrtl_string_equals(original, copy));
76+
77+
zrtl_string_free(original);
78+
zrtl_string_free(copy);
79+
ZRTL_PASS();
80+
}
81+
82+
ZRTL_TEST(test_string_equals) {
83+
ZrtlStringPtr a = zrtl_string_new("Hello");
84+
ZrtlStringPtr b = zrtl_string_new("Hello");
85+
ZrtlStringPtr c = zrtl_string_new("World");
86+
ZrtlStringPtr d = zrtl_string_new("Hell");
87+
88+
ZRTL_ASSERT(zrtl_string_equals(a, b)); /* Same content */
89+
ZRTL_ASSERT(!zrtl_string_equals(a, c)); /* Different content */
90+
ZRTL_ASSERT(!zrtl_string_equals(a, d)); /* Different length */
91+
92+
zrtl_string_free(a);
93+
zrtl_string_free(b);
94+
zrtl_string_free(c);
95+
zrtl_string_free(d);
96+
ZRTL_PASS();
97+
}
98+
99+
ZRTL_TEST(test_string_view) {
100+
ZrtlStringPtr str = zrtl_string_new("Test string");
101+
ZrtlStringView view = zrtl_string_view(str);
102+
103+
ZRTL_ASSERT_NOT_NULL(view.data);
104+
ZRTL_ASSERT_EQ(view.length, 11);
105+
ZRTL_ASSERT_EQ(view.data[0], 'T');
106+
107+
zrtl_string_free(str);
108+
ZRTL_PASS();
109+
}
110+
111+
/* ============================================================
112+
* Array Tests
113+
* ============================================================ */
114+
115+
ZRTL_TEST(test_array_create) {
116+
ZrtlArrayPtr arr = zrtl_array_new_i32(8);
117+
ZRTL_ASSERT_NOT_NULL(arr);
118+
ZRTL_ASSERT_EQ(ZRTL_ARRAY_LENGTH(arr), 0);
119+
ZRTL_ASSERT_GE(ZRTL_ARRAY_CAPACITY(arr), 8);
120+
121+
zrtl_array_free(arr);
122+
ZRTL_PASS();
123+
}
124+
125+
ZRTL_TEST(test_array_push) {
126+
ZrtlArrayPtr arr = zrtl_array_new_i32(4);
127+
ZRTL_ASSERT_NOT_NULL(arr);
128+
129+
arr = zrtl_array_push_i32(arr, 10);
130+
ZRTL_ASSERT_NOT_NULL(arr);
131+
ZRTL_ASSERT_EQ(ZRTL_ARRAY_LENGTH(arr), 1);
132+
ZRTL_ASSERT_EQ(zrtl_array_get_i32(arr, 0), 10);
133+
134+
arr = zrtl_array_push_i32(arr, 20);
135+
arr = zrtl_array_push_i32(arr, 30);
136+
ZRTL_ASSERT_EQ(ZRTL_ARRAY_LENGTH(arr), 3);
137+
ZRTL_ASSERT_EQ(zrtl_array_get_i32(arr, 1), 20);
138+
ZRTL_ASSERT_EQ(zrtl_array_get_i32(arr, 2), 30);
139+
140+
zrtl_array_free(arr);
141+
ZRTL_PASS();
142+
}
143+
144+
ZRTL_TEST(test_array_growth) {
145+
/* Start with small capacity to force growth */
146+
ZrtlArrayPtr arr = zrtl_array_new_i32(2);
147+
ZRTL_ASSERT_NOT_NULL(arr);
148+
149+
/* Push many elements to trigger reallocation */
150+
for (int i = 0; i < 100; i++) {
151+
arr = zrtl_array_push_i32(arr, i * 10);
152+
ZRTL_ASSERT_NOT_NULL(arr);
153+
}
154+
155+
ZRTL_ASSERT_EQ(ZRTL_ARRAY_LENGTH(arr), 100);
156+
157+
/* Verify all values are correct */
158+
for (int i = 0; i < 100; i++) {
159+
ZRTL_ASSERT_EQ(zrtl_array_get_i32(arr, i), i * 10);
160+
}
161+
162+
zrtl_array_free(arr);
163+
ZRTL_PASS();
164+
}
165+
166+
ZRTL_TEST(test_array_bounds) {
167+
ZrtlArrayPtr arr = zrtl_array_new_i32(4);
168+
arr = zrtl_array_push_i32(arr, 42);
169+
170+
/* Out of bounds access should return 0 */
171+
ZRTL_ASSERT_EQ(zrtl_array_get_i32(arr, 1), 0);
172+
ZRTL_ASSERT_EQ(zrtl_array_get_i32(arr, -1), 0);
173+
ZRTL_ASSERT_EQ(zrtl_array_get_i32(arr, 100), 0);
174+
175+
zrtl_array_free(arr);
176+
ZRTL_PASS();
177+
}
178+
179+
/* ============================================================
180+
* Iterator Tests
181+
* ============================================================ */
182+
183+
ZRTL_TEST(test_array_iterator) {
184+
ZrtlArrayPtr arr = zrtl_array_new_i32(4);
185+
arr = zrtl_array_push_i32(arr, 10);
186+
arr = zrtl_array_push_i32(arr, 20);
187+
arr = zrtl_array_push_i32(arr, 30);
188+
189+
ZrtlArrayIterator it = zrtl_array_iterator(arr);
190+
191+
ZRTL_ASSERT(zrtl_array_iterator_has_next(&it));
192+
ZRTL_ASSERT_EQ(zrtl_array_iterator_next_i32(&it), 10);
193+
194+
ZRTL_ASSERT(zrtl_array_iterator_has_next(&it));
195+
ZRTL_ASSERT_EQ(zrtl_array_iterator_next_i32(&it), 20);
196+
197+
ZRTL_ASSERT(zrtl_array_iterator_has_next(&it));
198+
ZRTL_ASSERT_EQ(zrtl_array_iterator_next_i32(&it), 30);
199+
200+
ZRTL_ASSERT(!zrtl_array_iterator_has_next(&it));
201+
202+
zrtl_array_free(arr);
203+
ZRTL_PASS();
204+
}
205+
206+
ZRTL_TEST(test_array_iterator_reset) {
207+
ZrtlArrayPtr arr = zrtl_array_new_i32(4);
208+
arr = zrtl_array_push_i32(arr, 5);
209+
arr = zrtl_array_push_i32(arr, 10);
210+
211+
ZrtlArrayIterator it = zrtl_array_iterator(arr);
212+
213+
/* Consume all elements */
214+
zrtl_array_iterator_next_i32(&it);
215+
zrtl_array_iterator_next_i32(&it);
216+
ZRTL_ASSERT(!zrtl_array_iterator_has_next(&it));
217+
218+
/* Reset and iterate again */
219+
zrtl_array_iterator_reset(&it);
220+
ZRTL_ASSERT(zrtl_array_iterator_has_next(&it));
221+
ZRTL_ASSERT_EQ(zrtl_array_iterator_next_i32(&it), 5);
222+
223+
zrtl_array_free(arr);
224+
ZRTL_PASS();
225+
}
226+
227+
ZRTL_TEST(test_string_iterator_bytes) {
228+
ZrtlStringPtr str = zrtl_string_new("ABC");
229+
ZrtlStringIterator it = zrtl_string_iterator(str);
230+
231+
ZRTL_ASSERT(zrtl_string_iterator_has_next(&it));
232+
ZRTL_ASSERT_EQ(zrtl_string_iterator_next_byte(&it), 'A');
233+
234+
ZRTL_ASSERT(zrtl_string_iterator_has_next(&it));
235+
ZRTL_ASSERT_EQ(zrtl_string_iterator_next_byte(&it), 'B');
236+
237+
ZRTL_ASSERT(zrtl_string_iterator_has_next(&it));
238+
ZRTL_ASSERT_EQ(zrtl_string_iterator_next_byte(&it), 'C');
239+
240+
ZRTL_ASSERT(!zrtl_string_iterator_has_next(&it));
241+
242+
zrtl_string_free(str);
243+
ZRTL_PASS();
244+
}
245+
246+
ZRTL_TEST(test_string_iterator_codepoints) {
247+
/* UTF-8 string: "Aé中" (A=1 byte, é=2 bytes, 中=3 bytes) */
248+
const char utf8[] = { 'A', 0xC3, 0xA9, 0xE4, 0xB8, 0xAD };
249+
ZrtlStringPtr str = zrtl_string_from_bytes(utf8, 6);
250+
ZrtlStringIterator it = zrtl_string_iterator(str);
251+
252+
/* 'A' = U+0041 */
253+
ZRTL_ASSERT(zrtl_string_iterator_has_next(&it));
254+
ZRTL_ASSERT_EQ(zrtl_string_iterator_next_codepoint(&it), 0x41);
255+
256+
/* 'é' = U+00E9 */
257+
ZRTL_ASSERT(zrtl_string_iterator_has_next(&it));
258+
ZRTL_ASSERT_EQ(zrtl_string_iterator_next_codepoint(&it), 0xE9);
259+
260+
/* '中' = U+4E2D */
261+
ZRTL_ASSERT(zrtl_string_iterator_has_next(&it));
262+
ZRTL_ASSERT_EQ(zrtl_string_iterator_next_codepoint(&it), 0x4E2D);
263+
264+
ZRTL_ASSERT(!zrtl_string_iterator_has_next(&it));
265+
266+
zrtl_string_free(str);
267+
ZRTL_PASS();
268+
}
269+
270+
/* ============================================================
271+
* DynamicBox Tests
272+
* ============================================================ */
273+
274+
ZRTL_TEST(test_box_i32) {
275+
int32_t value = 42;
276+
ZrtlDynamicBox box = zrtl_box_i32(&value);
277+
278+
ZRTL_ASSERT_EQ(box.tag, ZRTL_TAG_I32);
279+
ZRTL_ASSERT_EQ(box.size, sizeof(int32_t));
280+
ZRTL_ASSERT_NOT_NULL(box.data);
281+
ZRTL_ASSERT_EQ(zrtl_box_as_i32(&box), 42);
282+
283+
ZRTL_PASS();
284+
}
285+
286+
ZRTL_TEST(test_box_f64) {
287+
double value = 3.14159;
288+
ZrtlDynamicBox box = zrtl_box_f64(&value);
289+
290+
ZRTL_ASSERT_EQ(box.tag, ZRTL_TAG_F64);
291+
ZRTL_ASSERT_FLOAT_EQ(zrtl_box_as_f64(&box), 3.14159, 0.00001);
292+
293+
ZRTL_PASS();
294+
}
295+
296+
ZRTL_TEST(test_box_clone) {
297+
int32_t value = 100;
298+
ZrtlDynamicBox original = zrtl_box_i32(&value);
299+
300+
/* Clone creates a heap copy */
301+
ZrtlDynamicBox clone = zrtl_box_clone(&original);
302+
303+
ZRTL_ASSERT_NE(original.data, clone.data); /* Different memory */
304+
ZRTL_ASSERT_EQ(zrtl_box_as_i32(&clone), 100); /* Same value */
305+
ZRTL_ASSERT_NOT_NULL(clone.dropper); /* Has destructor */
306+
307+
zrtl_box_free(&clone);
308+
ZRTL_PASS();
309+
}
310+
311+
/* ============================================================
312+
* Type Tag Tests
313+
* ============================================================ */
314+
315+
ZRTL_TEST(test_type_tags) {
316+
/* Verify tag construction and extraction */
317+
ZrtlTypeTag tag = ZRTL_MAKE_TAG(ZRTL_CAT_INT, ZRTL_PRIM_32, ZRTL_FLAG_NULLABLE);
318+
319+
ZRTL_ASSERT_EQ(ZRTL_TAG_CATEGORY(tag), ZRTL_CAT_INT);
320+
ZRTL_ASSERT_EQ(ZRTL_TAG_TYPE_ID(tag), ZRTL_PRIM_32);
321+
ZRTL_ASSERT_EQ(ZRTL_TAG_FLAGS(tag), ZRTL_FLAG_NULLABLE);
322+
323+
/* Verify pre-defined tags */
324+
ZRTL_ASSERT_EQ(ZRTL_TAG_CATEGORY(ZRTL_TAG_VOID), ZRTL_CAT_VOID);
325+
ZRTL_ASSERT_EQ(ZRTL_TAG_CATEGORY(ZRTL_TAG_BOOL), ZRTL_CAT_BOOL);
326+
ZRTL_ASSERT_EQ(ZRTL_TAG_CATEGORY(ZRTL_TAG_STRING), ZRTL_CAT_STRING);
327+
328+
ZRTL_PASS();
329+
}
330+
331+
/* ============================================================
332+
* Test Main
333+
* ============================================================ */
334+
335+
ZRTL_TEST_MAIN(
336+
/* String tests */
337+
ZRTL_RUN(test_string_create),
338+
ZRTL_RUN(test_string_empty),
339+
ZRTL_RUN(test_string_from_bytes),
340+
ZRTL_RUN(test_string_copy),
341+
ZRTL_RUN(test_string_equals),
342+
ZRTL_RUN(test_string_view),
343+
344+
/* Array tests */
345+
ZRTL_RUN(test_array_create),
346+
ZRTL_RUN(test_array_push),
347+
ZRTL_RUN(test_array_growth),
348+
ZRTL_RUN(test_array_bounds),
349+
350+
/* Iterator tests */
351+
ZRTL_RUN(test_array_iterator),
352+
ZRTL_RUN(test_array_iterator_reset),
353+
ZRTL_RUN(test_string_iterator_bytes),
354+
ZRTL_RUN(test_string_iterator_codepoints),
355+
356+
/* Box tests */
357+
ZRTL_RUN(test_box_i32),
358+
ZRTL_RUN(test_box_f64),
359+
ZRTL_RUN(test_box_clone),
360+
ZRTL_RUN(test_type_tags)
361+
)

sdk/zrtl/Cargo.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[package]
2+
name = "zrtl"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "Zyntax Runtime Library - Types and utilities for ZRTL plugins"
6+
license = "Apache-2.0"
7+
repository = "https://github.com/darmie/zyntax"
8+
keywords = ["compiler", "jit", "runtime", "ffi", "interop"]
9+
categories = ["development-tools::ffi", "compilers"]
10+
11+
[dependencies]
12+
inventory = "0.3"
13+
14+
[features]
15+
default = []
16+
# Enable test harness macros
17+
test-harness = []

0 commit comments

Comments
 (0)