update: context
This commit is contained in:
parent
e9c042a654
commit
164e68e94c
3 changed files with 131 additions and 4 deletions
51
src/context.zig
Normal file
51
src/context.zig
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
pub const Value = union(enum) {
|
||||||
|
null,
|
||||||
|
bool: bool,
|
||||||
|
int: i64,
|
||||||
|
float: f64,
|
||||||
|
string: []const u8,
|
||||||
|
list: []const Value,
|
||||||
|
dict: std.StringHashMapUnmanaged(Value),
|
||||||
|
|
||||||
|
pub fn deinit(self: Value) void {
|
||||||
|
_ = self; // nada — a arena libera tudo
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Context = struct {
|
||||||
|
arena: std.heap.ArenaAllocator,
|
||||||
|
map: std.StringHashMapUnmanaged(Value),
|
||||||
|
|
||||||
|
pub fn init(child_allocator: std.mem.Allocator) Context {
|
||||||
|
const arena = std.heap.ArenaAllocator.init(child_allocator);
|
||||||
|
return .{
|
||||||
|
.arena = arena,
|
||||||
|
.map = .{},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocator(self: *Context) std.mem.Allocator {
|
||||||
|
return self.arena.allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Context) void {
|
||||||
|
self.arena.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set(self: *Context, key: []const u8, value: Value) !void {
|
||||||
|
const gop = try self.map.getOrPut(self.allocator(), key);
|
||||||
|
if (gop.found_existing) {
|
||||||
|
// opcional: deinit value antigo se necessário
|
||||||
|
// mas como arena libera tudo, não precisa
|
||||||
|
} else {
|
||||||
|
gop.key_ptr.* = try self.allocator().dupe(u8, key);
|
||||||
|
}
|
||||||
|
gop.value_ptr.* = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self: *const Context, key: []const u8) ?Value {
|
||||||
|
return self.map.get(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
76
src/context_test.zig
Normal file
76
src/context_test.zig
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const testing = std.testing;
|
||||||
|
const Context = @import("context.zig").Context;
|
||||||
|
const Value = @import("context.zig").Value;
|
||||||
|
|
||||||
|
test "context com arena" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
var ctx = Context.init(allocator);
|
||||||
|
defer ctx.deinit();
|
||||||
|
|
||||||
|
try ctx.set("nome", Value{ .string = "Lucas" }); // sem dupe!
|
||||||
|
try ctx.set("idade", Value{ .int = 30 });
|
||||||
|
|
||||||
|
try testing.expectEqualStrings("Lucas", ctx.get("nome").?.string);
|
||||||
|
try testing.expectEqual(@as(i64, 30), ctx.get("idade").?.int);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "context todos os tipos" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
var ctx = Context.init(allocator);
|
||||||
|
defer ctx.deinit();
|
||||||
|
|
||||||
|
// null
|
||||||
|
try ctx.set("nulo", Value{ .null = {} });
|
||||||
|
try testing.expectEqual(ctx.get("nulo").?, .null);
|
||||||
|
|
||||||
|
// bool
|
||||||
|
try ctx.set("verdadeiro", Value{ .bool = true });
|
||||||
|
try ctx.set("falso", Value{ .bool = false });
|
||||||
|
try testing.expect(ctx.get("verdadeiro").?.bool == true);
|
||||||
|
try testing.expect(ctx.get("falso").?.bool == false);
|
||||||
|
|
||||||
|
// int
|
||||||
|
try ctx.set("idade", Value{ .int = 30 });
|
||||||
|
try testing.expect(ctx.get("idade").?.int == 30);
|
||||||
|
|
||||||
|
// float
|
||||||
|
try ctx.set("preco", Value{ .float = 99.99 });
|
||||||
|
try testing.expectApproxEqAbs(@as(f64, 99.99), ctx.get("preco").?.float, 0.001);
|
||||||
|
|
||||||
|
// string
|
||||||
|
try ctx.set("nome", Value{ .string = "Lucas" });
|
||||||
|
try testing.expectEqualStrings("Lucas", ctx.get("nome").?.string);
|
||||||
|
|
||||||
|
// list
|
||||||
|
var list = try allocator.alloc(Value, 3);
|
||||||
|
defer allocator.free(list);
|
||||||
|
|
||||||
|
list[0] = Value{ .int = 1 };
|
||||||
|
list[1] = Value{ .int = 2 };
|
||||||
|
list[2] = Value{ .int = 3 };
|
||||||
|
|
||||||
|
try ctx.set("numeros", Value{ .list = list });
|
||||||
|
const numeros = ctx.get("numeros").?.list;
|
||||||
|
try testing.expectEqual(@as(usize, 3), numeros.len);
|
||||||
|
try testing.expect(numeros[0].int == 1);
|
||||||
|
try testing.expect(numeros[1].int == 2);
|
||||||
|
try testing.expect(numeros[2].int == 3);
|
||||||
|
|
||||||
|
// dict
|
||||||
|
var dict = std.StringHashMapUnmanaged(Value){};
|
||||||
|
try dict.put(ctx.allocator(), "chave1", Value{ .string = "valor1" });
|
||||||
|
try dict.put(ctx.allocator(), "chave2", Value{ .int = 42 });
|
||||||
|
try ctx.set("config", Value{ .dict = dict });
|
||||||
|
const config = ctx.get("config").?.dict;
|
||||||
|
try testing.expectEqualStrings("valor1", config.get("chave1").?.string);
|
||||||
|
try testing.expect(config.get("chave2").?.int == 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "failback" {
|
||||||
|
const allocator = testing.allocator;
|
||||||
|
var ctx = Context.init(allocator);
|
||||||
|
defer ctx.deinit();
|
||||||
|
|
||||||
|
try testing.expectEqual(ctx.get("nome"), null);
|
||||||
|
}
|
||||||
8
todo.md
8
todo.md
|
|
@ -22,10 +22,10 @@
|
||||||
- [x] regroup
|
- [x] regroup
|
||||||
- [x] resetcycle
|
- [x] resetcycle
|
||||||
- [x] spaceless
|
- [x] spaceless
|
||||||
- [ ] templatetag
|
- [x] templatetag
|
||||||
- [x] url
|
- [x] url
|
||||||
- [x] verbatim
|
- [x] verbatim
|
||||||
- [ ] widthratio
|
- [x] widthratio
|
||||||
- [x] with
|
- [x] with
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -114,8 +114,8 @@ ___
|
||||||
- [x] querystring
|
- [x] querystring
|
||||||
- [x] regroup
|
- [x] regroup
|
||||||
- [x] resetcycle
|
- [x] resetcycle
|
||||||
- [ ] templatetag
|
- [x] templatetag
|
||||||
- [ ] widthratio
|
- [x] widthratio
|
||||||
|
|
||||||
2 - projetar o Context com calma:
|
2 - projetar o Context com calma:
|
||||||
- Estrutura hierárquica (escopos aninhados para with, for, etc.)
|
- Estrutura hierárquica (escopos aninhados para with, for, etc.)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue