Interface struct ‣ File ᴾᴴᴾ - chung-leong/zigar GitHub Wiki
JavaScript | PHP
The std.fs.File struct provides an interface to a file in Zig. When used as an argument to function exported to PHP, it accepts a PHP stream resource. During the conversion process a virtual file descriptor is created. This file descriptor is closed automatically when the resource is freed.
The following example prints the contents of a PHP memory stream:
const std = @import("std");
pub fn print(file: std.fs.File) !void {
var write_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&write_buffer);
const stdout = &stdout_writer.interface;
var read_buffer: [1024]u8 = undefined;
while (true) {
const len = try file.read(&read_buffer);
if (len == 0) break;
_ = try stdout.write(read_buffer[0..len]);
}
try stdout.flush();
}
<?php
$m = zigar_use(__DIR__ . '/file-example-1.zig');
$strm = fopen("php://memory", "w+");
for ($i = 0; $i < 3; $i++) {
fwrite($strm, "Hello world\n");
}
rewind($strm);
$m->print($strm);
fclose($strm);
Hello world
Hello world
Hello world
This happens even when the resource isn't freed explicitly:
const std = @import("std");
var copy: std.fs.File = undefined;
pub fn print(file: std.fs.File) !void {
// save a copy for printAgain()
copy = file;
var write_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&write_buffer);
const stdout = &stdout_writer.interface;
var read_buffer: [1024]u8 = undefined;
while (true) {
const len = try file.read(&read_buffer);
if (len == 0) break;
_ = try stdout.write(read_buffer[0..len]);
}
try stdout.flush();
}
pub fn printAgain() !void {
try print(copy);
}
<?php
$m = zigar_use(__DIR__ . '/file-example-6.zig');
$strm = fopen("php://memory", "w+");
for ($i = 0; $i < 3; $i++) {
fwrite($strm, "Hello world\n");
}
rewind($strm);
$m->print($strm);
rewind($strm);
$m->printAgain();
// this prints nothing since the file offset is at the end
$m->printAgain();
$strm = null;
// the file descriptor is not valid at this point
try {
$m->printAgain();
} catch (Exception $e) {
echo "$e\n";
}
Hello world
Hello world
Hello world
Hello world
Hello world
Hello world
ZigException: not open for reading in /home/rwiggum/examples/file-example-6.php:18
Stack trace:
#0 /home/rwiggum/examples/file-example-6.php(18): file-example-6->printAgain()
#1 {main}
The file descriptor can be used to close the file on the Zig side:
const std = @import("std");
pub fn print(file: std.fs.File) !void {
defer file.close();
var write_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&write_buffer);
const stdout = &stdout_writer.interface;
var read_buffer: [1024]u8 = undefined;
while (true) {
const len = try file.read(&read_buffer);
if (len == 0) break;
_ = try stdout.write(read_buffer[0..len]);
}
try stdout.flush();
}
<?php
$m = zigar_use(__DIR__ . '/file-example-5.zig');
$strm = fopen("php://memory", "w+");
fwrite($strm, "Hello world\n");
rewind($strm);
$m->print($strm);
// this call will fail
fclose($strm);
Hello world
PHP Fatal error: Uncaught TypeError: fclose(): supplied resource is not a valid stream resource in /home/rwiggum/examples/file-example-5.php:10
Note:
Calling std.fs.File.stat() with a virtual file will crash on Linux on non-x86 platforms due to the use of direct syscalls.