tiny.css.selector.nth
Defined in selector.
API (5)
Actions
Public operations.
matches: Whether a one basedindexout ofcountsiblings satisfiesAn+B.parse: Parsesodd,even,An+B,n, or a bare integer.
Types and contracts
Public types and contracts.
Coefficients: The coefficients of anAn+Bexpression.Kind: Which sibling sequence a structural pseudo-class counts over.Nth: OneAn+Btest.
Source
Source: lib/css/src/selector/nth.zig
zig
const std = @import("std");/// Which sibling sequence a structural pseudo-class counts over.pub const Kind = enum(u8) { child, last_child, of_type, last_of_type,};/// One `An+B` test. `next` chains further structural tests on the same/// compound, one based, so that `Compound.nth` stays a single word.pub const Nth = struct { a: i32, b: i32, kind: Kind, next: u32 = 0,};/// The coefficients of an `An+B` expression.pub const Coefficients = struct { a: i32, b: i32,};/// Parses `odd`, `even`, `An+B`, `n`, or a bare integer.pub fn parse(text: []const u8) ?Coefficients { const trimmed = std.mem.trim(u8, text, " \t\r\n\x0C"); if (trimmed.len == 0) return null; if (std.ascii.eqlIgnoreCase(trimmed, "odd")) return .{ .a = 2, .b = 1 }; if (std.ascii.eqlIgnoreCase(trimmed, "even")) return .{ .a = 2, .b = 0 }; const split = std.mem.indexOfAny(u8, trimmed, "nN") orelse { return .{ .a = 0, .b = integer(trimmed) orelse return null }; }; const head = std.mem.trim(u8, trimmed[0..split], " \t\r\n\x0C"); const tail = std.mem.trim(u8, trimmed[split + 1 ..], " \t\r\n\x0C"); const a = coefficient(head) orelse return null; if (tail.len == 0) return .{ .a = a, .b = 0 }; const sign: i32 = switch (tail[0]) { '+' => 1, '-' => -1, else => return null, }; const rest = std.mem.trim(u8, tail[1..], " \t\r\n\x0C"); const magnitude = integer(rest) orelse return null; if (magnitude < 0) return null; return .{ .a = a, .b = sign * magnitude };}/// Whether a one based `index` out of `count` siblings satisfies `An+B`.pub fn matches(coefficients: Coefficients, index: u32, count: u32, kind: Kind) bool { std.debug.assert(index >= 1); if (count != 0) std.debug.assert(index <= count); const last = kind == .last_child or kind == .last_of_type; const position: i64 = if (last) @as(i64, count) - @as(i64, index) + 1 else @as(i64, index); const b: i64 = coefficients.b; if (coefficients.a == 0) return position == b; const offset = position - b; const a: i64 = coefficients.a; if (@rem(offset, a) != 0) return false; return @divTrunc(offset, a) >= 0;}fn coefficient(head: []const u8) ?i32 { if (head.len == 0) return 1; if (head.len == 1 and head[0] == '+') return 1; if (head.len == 1 and head[0] == '-') return -1; return integer(head);}fn integer(text: []const u8) ?i32 { if (text.len == 0) return null; var index: usize = 0; var sign: i32 = 1; if (text[0] == '+' or text[0] == '-') { sign = if (text[0] == '-') -1 else 1; index = 1; } if (index >= text.len) return null; var magnitude: i32 = 0; while (index < text.len) : (index += 1) { if (!std.ascii.isDigit(text[index])) return null; magnitude = std.math.mul(i32, magnitude, 10) catch return null; magnitude = std.math.add(i32, magnitude, text[index] - '0') catch return null; } return sign * magnitude;}test "an nth expression parses its keywords, coefficients, and offsets" { try std.testing.expectEqual(Coefficients{ .a = 2, .b = 1 }, parse("odd").?); try std.testing.expectEqual(Coefficients{ .a = 2, .b = 0 }, parse("EVEN").?); try std.testing.expectEqual(Coefficients{ .a = 0, .b = 3 }, parse("3").?); try std.testing.expectEqual(Coefficients{ .a = 3, .b = 1 }, parse("3n + 1").?); try std.testing.expectEqual(Coefficients{ .a = -1, .b = 3 }, parse("-n+3").?); try std.testing.expectEqual(Coefficients{ .a = 1, .b = 0 }, parse("n").?); try std.testing.expectEqual(Coefficients{ .a = 1, .b = -2 }, parse("+n-2").?); try std.testing.expect(parse("") == null); try std.testing.expect(parse("2x+1") == null); try std.testing.expect(parse("2n*1") == null);}test "a fixed index matches only its own position" { const first = Coefficients{ .a = 0, .b = 1 }; try std.testing.expect(matches(first, 1, 5, .child)); try std.testing.expect(!matches(first, 2, 5, .child)); try std.testing.expect(matches(first, 5, 5, .last_child)); try std.testing.expect(!matches(first, 4, 5, .last_child));}test "a stepped expression matches its arithmetic sequence forward only" { const odd = Coefficients{ .a = 2, .b = 1 }; try std.testing.expect(matches(odd, 1, 6, .child)); try std.testing.expect(!matches(odd, 2, 6, .child)); try std.testing.expect(matches(odd, 5, 6, .child)); const leading = Coefficients{ .a = -1, .b = 3 }; try std.testing.expect(matches(leading, 1, 9, .child)); try std.testing.expect(matches(leading, 3, 9, .child)); try std.testing.expect(!matches(leading, 4, 9, .child));}Source: lib/css/src/selector/root.zig:19
zig
pub const nth = nth_expression;Audit
| Definitions | 6 |
|---|---|
| Public names | 6 |
| Members | 10 |
| Version | 26.7.0 |
| Revision | daab053ee433 |