Compare commits
4 Commits
ad73ea6508
...
e562e30e5e
Author | SHA1 | Date | |
---|---|---|---|
e562e30e5e | |||
8aaceba484 | |||
c74d615131 | |||
8ccb2c3a66 |
@ -5,12 +5,12 @@ pub fn build(b: *std.Build) void {
|
|||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
|
|
||||||
const nice = b.addModule("nice", .{
|
const nice = b.addModule("nice", .{
|
||||||
.root_source_file = .{ .path = "src/nice.zig" },
|
.root_source_file = b.path("src/nice.zig"),
|
||||||
});
|
});
|
||||||
|
|
||||||
const tests = b.addTest(.{
|
const tests = b.addTest(.{
|
||||||
.name = "nice-unit-tests",
|
.name = "nice-unit-tests",
|
||||||
.root_source_file = .{ .path = "tests/main.zig" },
|
.root_source_file = b.path("tests/main.zig"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
@ -50,7 +50,7 @@ pub fn add_examples(b: *std.Build, options: ExampleOptions) void {
|
|||||||
inline for (examples) |example| {
|
inline for (examples) |example| {
|
||||||
const ex_exe = b.addExecutable(.{
|
const ex_exe = b.addExecutable(.{
|
||||||
.name = example.name,
|
.name = example.name,
|
||||||
.root_source_file = .{ .path = example.file },
|
.root_source_file = b.path(example.file),
|
||||||
.target = options.target,
|
.target = options.target,
|
||||||
.optimize = .Debug,
|
.optimize = .Debug,
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
.{
|
.{
|
||||||
.name = "nice-data",
|
.name = "nice",
|
||||||
.version = "0.1.0-pre",
|
.version = "0.1.0-pre",
|
||||||
.dependencies = .{},
|
.dependencies = .{},
|
||||||
.paths = .{
|
.paths = .{
|
||||||
|
@ -267,7 +267,6 @@ nests:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Restrictions
|
## Restrictions
|
||||||
|
|
||||||
Nice documents must be encoded in valid UTF-8 with no BOM. They must use `LF`-only newlines (`CR` characters are forbidden). Tabs and spaces cannot be mixed for indentation. Indentation *must* adhere to a consistent quantum throughout the whole document, including on comment lines. Nonprinting ASCII characters are forbidden (specifically, any character less than `0x20` (space) except for `0x09` (horizontal tab) and `0x0A` (newline)). Trailing whitespace, including lines consisting only of whitespace, is forbidden, although empty lines are permitted. Some keys and values cannot be represented (for example, map keys cannot start with the character `#`, though map values can).
|
Nice documents must be encoded in valid UTF-8 with no BOM. They must use `LF`-only newlines (`CR` characters are forbidden). Tabs and spaces cannot be mixed for indentation. Indentation *must* adhere to a consistent quantum throughout the whole document, including on comment lines. Nonprinting ASCII characters are forbidden (specifically, any character less than `0x20` (space) except for `0x09` (horizontal tab) and `0x0A` (newline)). Trailing whitespace, including lines consisting only of whitespace, is forbidden, although empty lines are permitted. Some keys and values cannot be represented (for example, map keys cannot start with the character `#`, though map values can).
|
||||||
@ -286,7 +285,7 @@ Nice is not, and does not try to be, a general-purpose data serialization format
|
|||||||
|
|
||||||
### There's No Need to Conquer the World
|
### There's No Need to Conquer the World
|
||||||
|
|
||||||
Nice has no exhaustive specification or formal grammar. The parser is handwritten, and there are pretty much guaranteed to be some strange edge cases that weren't considered when writing it. Standardization is a good thing, generally speaking, but it's not a goal here. Perhaps this driven by the author's indolence more than deep philosophical zealotry. On the other hand, this paragraph is under the philosophy section.
|
Nice has no exhaustive specification or formal grammar. The parser is handwritten, and there are pretty much guaranteed to be some strange edge cases that weren't considered when writing it. Standardization is a good thing, generally speaking, but it's not a goal here. Perhaps this is driven by the author's indolence more than deep philosophical zealotry. On the other hand, this paragraph is under the philosophy section.
|
||||||
|
|
||||||
# The Implementation
|
# The Implementation
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ pub const Options = struct {
|
|||||||
falsy_boolean_scalars: []const []const u8 = &.{ "false", "False", "no", "off" },
|
falsy_boolean_scalars: []const []const u8 = &.{ "false", "False", "no", "off" },
|
||||||
|
|
||||||
// Only used by the parseTo family of functions.
|
// Only used by the parseTo family of functions.
|
||||||
// A list of strings. Scalars in the doucment that match any of the values listed
|
// A list of strings. Scalars in the document that match any of the values listed
|
||||||
// will be parsed to optional `null`. Any other scalar value will be parsed as the
|
// will be parsed to optional `null`. Any other scalar value will be parsed as the
|
||||||
// optional child type if the destination type is an optional. By default, these
|
// optional child type if the destination type is an optional. By default, these
|
||||||
// comparisons are case-sensitive. See the `case_insensitive_scalar_coersion`
|
// comparisons are case-sensitive. See the `case_insensitive_scalar_coersion`
|
||||||
|
@ -68,6 +68,10 @@ pub const Value = union(enum) {
|
|||||||
map: Map,
|
map: Map,
|
||||||
inline_map: Map,
|
inline_map: Map,
|
||||||
|
|
||||||
|
pub fn FieldConverter(comptime T: type) type {
|
||||||
|
return *const fn (Value, std.mem.Allocator, Options) error{BadValue}!T;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn convertTo(self: Value, comptime T: type, allocator: std.mem.Allocator, options: Options) !T {
|
pub fn convertTo(self: Value, comptime T: type, allocator: std.mem.Allocator, options: Options) !T {
|
||||||
switch (@typeInfo(T)) {
|
switch (@typeInfo(T)) {
|
||||||
.Void => {
|
.Void => {
|
||||||
@ -209,39 +213,28 @@ pub const Value = union(enum) {
|
|||||||
.map, .inline_map => |map| {
|
.map, .inline_map => |map| {
|
||||||
var result: T = undefined;
|
var result: T = undefined;
|
||||||
|
|
||||||
if (options.ignore_extra_fields) {
|
if (!options.ignore_extra_fields and (map.count() > stt.fields.len))
|
||||||
inline for (stt.fields) |field| {
|
return error.BadValue;
|
||||||
if (map.get(field.name)) |value| {
|
|
||||||
@field(result, field.name) = try value.convertTo(field.type, allocator, options);
|
var use_count: usize = 0;
|
||||||
} else if (options.allow_omitting_default_values) {
|
inline for (stt.fields) |field| {
|
||||||
if (comptime field.default_value) |def|
|
if (map.get(field.name)) |val| {
|
||||||
@field(result, field.name) = @as(*align(1) const field.type, @ptrCast(def)).*
|
if (comptime hasFn(T, "niceFieldConverter") and T.niceFieldConverter(field.name) != null) {
|
||||||
else
|
@field(result, field.name) = try T.niceFieldConverter(field.name).?(val, allocator, options);
|
||||||
return error.BadValue;
|
|
||||||
} else {
|
} else {
|
||||||
return error.BadValue;
|
@field(result, field.name) = try val.convertTo(field.type, allocator, options);
|
||||||
}
|
}
|
||||||
}
|
use_count += 1;
|
||||||
} else {
|
} else if (options.allow_omitting_default_values) {
|
||||||
// TODO: consider not cloning the map here. This would
|
if (comptime field.default_value) |def|
|
||||||
// result in the requirement that the raw value object
|
@field(result, field.name) = @as(*align(1) const field.type, @ptrCast(def)).*
|
||||||
// not be used after it has been converted to a type,
|
else
|
||||||
// based on the parse options.
|
return error.BadValue;
|
||||||
var clone = try map.clone();
|
} else return error.BadValue;
|
||||||
defer clone.deinit();
|
|
||||||
inline for (stt.fields) |field| {
|
|
||||||
if (clone.fetchSwapRemove(field.name)) |kv| {
|
|
||||||
@field(result, field.name) = try kv.value.convertTo(field.type, allocator, options);
|
|
||||||
} else if (options.allow_omitting_default_values) {
|
|
||||||
if (comptime field.default_value) |def|
|
|
||||||
@field(result, field.name) = @as(*align(1) const field.type, @ptrCast(def)).*
|
|
||||||
else
|
|
||||||
return error.BadValue;
|
|
||||||
} else return error.BadValue;
|
|
||||||
}
|
|
||||||
// there were extra fields in the data
|
|
||||||
if (clone.count() > 0) return error.BadValue;
|
|
||||||
}
|
}
|
||||||
|
// there were extra fields in the data
|
||||||
|
if (!options.ignore_extra_fields and (map.count() > use_count))
|
||||||
|
return error.BadValue;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user