Skip to content

Instantly share code, notes, and snippets.

@jdmichaud
Last active September 11, 2024 12:36
Show Gist options
  • Save jdmichaud/b75ee234bfa87283a6337e06a3b70767 to your computer and use it in GitHub Desktop.
Save jdmichaud/b75ee234bfa87283a6337e06a3b70767 to your computer and use it in GitHub Desktop.
Zig cheatsheet
https://ziglang.org/documentation/master/#Pointers
*T - single-item pointer to exactly one item.
Supports deref syntax: ptr.*
[*]T - pointer to unknown number of items. (eq. of *T in C)
Supports index syntax: ptr[i]
Supports slice syntax: ptr[start..end]
Supports pointer arithmetic: ptr + x, ptr - x
T must have a known size, which means that it cannot be anyopaque or any other opaque type.
*[N]T - pointer to N items, same as single-item pointer to an array.
Supports index syntax: array_ptr[i]
Supports slice syntax: array_ptr[start..end]
Supports len property: array_ptr.len
[]T - pointer to runtime-known number of items.
Supports index syntax: slice[i]
Supports slice syntax: slice[start..end]
Supports len property: slice.len
https://github.com/ziglang/zig/wiki/Zig-Newcomer-Programming-FAQs#what-is-a-t
What's inside the `[.]T` is the number of items.
`[n]T` is an array with a compile time known number of items.
`[*]T` means the number is indeterminate (like a kleene star). It's a pointer to an array of unknown size.
`[]T` is a slice, meaning it's a struct with a `[*]` and a size_t for the runtime known size of the array.
```c
const arr = [_]u8{ 5, 1, 8, 4, 5, 6 };
std.log.debug("arr: {}", .{ @TypeOf(arr) });
std.log.debug("&arr: {}", .{ @TypeOf(&arr) });
const sli: []const u8 = &arr;
std.log.debug("sli: {}", .{ @TypeOf(sli) });
std.log.debug("sli[0..]: {}", .{ @TypeOf(sli[0..]) });
std.log.debug("sli[0..].*: {}", .{ @TypeOf(sli[0..].*) });
var known_at_runtime_zero: usize = 3;
_ = &known_at_runtime_zero;
std.log.debug("sli[known_at_runtime_zero..][0..3].*: {}", .{ @TypeOf(sli[known_at_runtime_zero..][0..3].*) });
```
This will give:
```
arr: [6]u8
&arr: *const [6]u8
sli: []const u8
sli[0..]: *const [6]u8
sli[0..].*: [6]u8
```
Zig automatically converts &arr which is a pointer on the static array to a slice.
A slice is a (sort of) struct containing a pointer and a size (known at compile time here).
Then using `[0..]` we extract the pointer from the slice and with `.*` we dereference it back to a static array.
When the start position is known at runtime, we can still extract comptime known length slice by double slicing.
First from the runtime start position then from 0 to a static value. This gets us a comptime known array.
// Allocate a slice
const slice: []const u8 = try allocator.alloc(u8, 256);
const std = @import("std");
pub fn main() !void {
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = general_purpose_allocator.allocator();
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
const stdout = std.io.getStdOut().writer();
if (args.len != 1 and (std.mem.eql(u8, args[1], "--help") or std.mem.eql(u8, args[1], "-h"))) {
try stdout.print("{s} is a nice tool\n\n", .{ args[0] });
try stdout.print("usage:\n", .{});
try stdout.print(" {s} - Do something\n", .{ args[0] });
try stdout.print(" {s} parameter - Do something with a parameter\n", .{ args[0] });
return;
}
}
// Convert a slice of type A to a slice of type B
const src: []const u8 = ...;
const dest: []const u32 = @as(*const []const u32, @ptrCast(&src[0..])).*;
// Create a folder
const cwd = std.fs.cwd();
try cwd.makeDir("folder_name");
// Iterate over directory content...
var iter_dir = try std.fs.cwd().openIterableDir(
"folder_name",
.{},
);
// ...and count the number of files
var file_count: usize = 0;
var iter = iter_dir.iterate();
while (try iter.next()) |entry| {
if (entry.kind == .file) file_count += 1;
}
// reference: https://zig.guide/standard-library/filesystem/
// Create a file
const file = try std.fs.cwd().createFile(
"somefile.txt",
.{ .read = true },
);
defer file.close();
// Get file stats
const stat = try file.stat();
try expect(stat.size == 0);
try expect(stat.kind == .file);
try expect(stat.ctime <= std.time.nanoTimestamp());
try expect(stat.mtime <= std.time.nanoTimestamp());
try expect(stat.atime <= std.time.nanoTimestamp());
// Read file
const contents = try file.reader().readAllAlloc(
test_allocator,
256, // read 256 characters
);
defer test_allocator.free(contents);
// Write to file
const file = try std.fs.cwd().createFile(
"someotherfile.txt",
.{ .read = true },
);
defer file.close();
try file.writeAll("Some content");
const PakHeader = extern struct {
magic: [4]u8,
offset: u32,
size: u32,
};
const pak: []const u8 = ...;
const pakHeader: *const PakHeader = @ptrCast(&pak[0]);
try stdout.print("magic: {s}\n", .{ pakHeader.magic });
try stdout.print("offset: {}\n", .{ pakHeader.offset });
try stdout.print("size: {}\n", .{ pakHeader.size });
const std = @import("std");
fn load(pathname: []const u8) ![]align(4096) const u8 {
var file = try std.fs.cwd().openFile(pathname, .{});
defer file.close();
const size = try file.getEndPos();
const buffer = try std.posix.mmap(
null,
size,
std.posix.PROT.READ,
.{ .TYPE = .SHARED },
file.handle,
0,
);
errdefer std.posix.munmap(buffer);
return buffer;
}
// import ctypes
//
// class Quux(Structure):
// _pack_ = 1 # Necessary if your structure in align(1) in zig
// _fields_ = [
// ("field", c_uint32),
// ]
//
// lib = ctypes.CDLL("./libpython.so")
// # for ctypes everything is a i32, so this is necessary
// # to pass around 64 bits pointers
// lib.foo.restype = ctypes.c_void_p
// f = lib.foo()
// lib.bar.argtypes = (ctypes.c_void_p,)
// lib.bar(f)
//
// Build with: `zig build-lib python.zig -dynamic`
var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
const allocator = general_purpose_allocator.allocator();
// This function is extern and can be access directly by python
const Quux = extern struct {
field: u32,
};
// This struct is not extern and cannot be accessed directly.
// Use pointers as handlers.
const Foo = struct {
quuxes: []const Quux,
pub fn init() Foo {
const quuxes = &[_]Quux{ Quux{ .field = 42 } };
return Foo{
.quuxes = quuxes,
};
}
};
// This function is exported and accessible by python using ctypes
export fn foo() *Foo {
var f: *Foo = allocator.create(Foo);
f.* = Foo.init();
return &f;
}
// This function is exported and accessible by python using ctypes
export fn bar(f: *Foo) void {
std.log.debug("f.quuxes {any}", .{ f.quuxes[0] });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment