@@ -2452,6 +2452,74 @@ pub const Lua = opaque {
24522452 unreachable ;
24532453 }
24542454 }
2455+
2456+ /// Type for a string buffer. A string buffer allows building Lua strings piecemeal.
2457+ ///
2458+ /// Pattern of use:
2459+ /// 1. Declare a variable of type Buffer
2460+ /// 2. Initialize with bufferInit()
2461+ /// 3. Add string pieces using addX() functions
2462+ /// 4. Finish by calling pushResult()
2463+ ///
2464+ /// From: `typedef struct luaL_Buffer luaL_Buffer;`
2465+ /// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_Buffer
2466+ pub const Buffer = extern struct {
2467+ const BufferSize : usize = @intCast (c .LUAL_BUFFERSIZE );
2468+ p : ? [* ]u8 = null ,
2469+ lvl : c_int = 0 ,
2470+ L : ? * Lua = null ,
2471+ buffer : [BufferSize ]u8 = undefined ,
2472+
2473+ /// Adds the character c to the given buffer.
2474+ ///
2475+ /// From: `void luaL_addchar(luaL_Buffer *B, char c);`
2476+ /// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_addchar
2477+ /// Stack Behavior: `[-0, +0, m]`
2478+ pub fn addChar (buffer : * Buffer , char : u8 ) void {
2479+ assert (buffer .p != null and buffer .L != null ); // You must use `Lua.initBuffer(&Lua.Buffer)` before calling `Lua.Buffer.addChar()`.
2480+
2481+ if (buffer .p ) | ptr | {
2482+ // if the buffer is out of capacity, we will want to call `prepbuffer` to get more space and change the pointer.
2483+ var ptr_copy = ptr ;
2484+
2485+ if (@intFromPtr (ptr ) >= @intFromPtr (& buffer .buffer ) + c .LUAL_BUFFERSIZE ) {
2486+ const extra = c .luaL_prepbuffer (@ptrCast (buffer ));
2487+ assert (extra != null );
2488+ ptr_copy = extra ;
2489+ }
2490+
2491+ // We can assert buffer.p is non-null here since prepbuffer guarantees it
2492+ ptr_copy [0 ] = char ;
2493+ buffer .p = ptr_copy + 1 ;
2494+ } else {
2495+ std .debug .panic (
2496+ "Failed to add character '{c}' to a buffer: the buffer is not initialized, `buffer.p` is null.\n " ,
2497+ .{char },
2498+ );
2499+ }
2500+ }
2501+
2502+ /// Finishes the use of the buffer leaving the final string on the top of the stack.
2503+ ///
2504+ /// From: `void luaL_pushresult(luaL_Buffer *B);`
2505+ /// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_pushresult
2506+ /// Stack Behavior: `[-?, +1, m]`
2507+ pub fn pushResult (buffer : * Lua.Buffer ) void {
2508+ assert (buffer .p != null and buffer .L != null ); // You must use `Lua.initBuffer(&Lua.Buffer)` before calling `Lua.Buffer.pushResult()`.
2509+
2510+ return c .luaL_pushresult (@ptrCast (buffer ));
2511+ }
2512+ };
2513+
2514+ /// Initializes a Lua buffer. This function does not allocate any space;
2515+ /// the buffer must be declared as a variable.
2516+ ///
2517+ /// From: `void luaL_buffinit(lua_State *L, luaL_Buffer *B);`
2518+ /// Refer to: https://www.lua.org/manual/5.1/manual.html#luaL_buffinit
2519+ /// Stack Behavior: `[-0, +0, -]`
2520+ pub fn initBuffer (lua : * Lua , buffer : * Lua.Buffer ) void {
2521+ return c .luaL_buffinit (asState (lua ), @ptrCast (buffer ));
2522+ }
24552523};
24562524
24572525test "Lua can be initialized with an allocator" {
@@ -4679,3 +4747,45 @@ test "callMeta() should do nothing when it is not defined" {
46794747 try std .testing .expect (lua .isTable (-1 ));
46804748 try std .testing .expectEqual (1 , lua .getTop ());
46814749}
4750+
4751+ test "Buffer should be able to build character by character" {
4752+ const lua = try Lua .init (std .testing .allocator );
4753+ defer lua .deinit ();
4754+
4755+ var b : Lua.Buffer = .{};
4756+ lua .initBuffer (& b );
4757+ b .addChar ('H' );
4758+ b .addChar ('e' );
4759+ b .addChar ('l' );
4760+ b .addChar ('l' );
4761+ b .addChar ('o' );
4762+ b .addChar (',' );
4763+ b .addChar (' ' );
4764+ b .addChar ('w' );
4765+ b .addChar ('o' );
4766+ b .addChar ('r' );
4767+ b .addChar ('l' );
4768+ b .addChar ('d' );
4769+ b .addChar ('!' );
4770+ b .pushResult ();
4771+
4772+ try std .testing .expectEqual (1 , lua .getTop ());
4773+ try std .testing .expect (lua .isString (-1 ));
4774+ try std .testing .expectEqualStrings ("Hello, world!" , try lua .toLString (-1 ));
4775+ }
4776+
4777+ test "Buffer should handle very long string" {
4778+ const lua = try Lua .init (std .testing .allocator );
4779+ defer lua .deinit ();
4780+
4781+ var b : Lua.Buffer = .{};
4782+ lua .initBuffer (& b );
4783+ for (0.. 256_000) | i | {
4784+ b .addChar ('0' + @as (u8 , @intCast ((i % 10 ))));
4785+ }
4786+ b .pushResult ();
4787+
4788+ try std .testing .expectEqual (1 , lua .getTop ());
4789+ try std .testing .expect (lua .isString (-1 ));
4790+ try std .testing .expectEqualStrings ("0123456789" ** 25_600 , try lua .toLString (-1 ));
4791+ }
0 commit comments