Added build step to .

This commit is contained in:
00JCIV00 2024-02-22 16:54:07 -05:00 committed by Tim Culverhouse
parent ca4346e35a
commit 845a3a6786
99 changed files with 94410 additions and 0 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
zig-cache/ zig-cache/
zig-out/ zig-out/
*.log *.log
Session*.*vim

10270
docs/commonmark.js Normal file

File diff suppressed because it is too large Load diff

1
docs/data-astNodes.js Normal file

File diff suppressed because one or more lines are too long

1
docs/data-calls.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
docs/data-decls.js Normal file

File diff suppressed because one or more lines are too long

1
docs/data-exprs.js Normal file

File diff suppressed because one or more lines are too long

1
docs/data-files.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
var guideSections =[{"name":"","guides":[]}];

1
docs/data-modules.js Normal file
View file

@ -0,0 +1 @@
var modules =[{"name":"main","file":0,"main":66,"table":{"builtin":1,"zigimg":3,"ziglyph":2,"main":0}},{"name":"builtin","file":0,"main":462,"table":{}},{"name":"ziglyph","file":0,"main":32522,"table":{}},{"name":"zigimg","file":0,"main":34283,"table":{"builtin":4}},{"name":"builtin","file":0,"main":34497,"table":{}}];

1
docs/data-rootMod.js Normal file
View file

@ -0,0 +1 @@
var rootMod =0;

1
docs/data-typeKinds.js Normal file
View file

@ -0,0 +1 @@
var typeKinds =["Unanalyzed","Type","Void","Bool","NoReturn","Int","Float","Pointer","Array","Struct","ComptimeExpr","ComptimeFloat","ComptimeInt","Undefined","Null","Optional","ErrorUnion","InferredErrorUnion","ErrorSet","Enum","Union","Fn","Opaque","Frame","AnyFrame","Vector","EnumLiteral"];

1
docs/data-types.js Normal file

File diff suppressed because one or more lines are too long

1245
docs/index.html Normal file

File diff suppressed because it is too large Load diff

5242
docs/main.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,233 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>builtin.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-comment">/// Zig version. When writing code that supports multiple versions of Zig, prefer</span></span>
<span class="line" id="L3"><span class="tok-comment">/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.</span></span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> zig_version = std.SemanticVersion.parse(zig_version_string) <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> zig_version_string = <span class="tok-str">&quot;0.12.0-dev.2824+0b7af2563&quot;</span>;</span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> zig_backend = std.builtin.CompilerBackend.stage2_llvm;</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> output_mode = std.builtin.OutputMode.Exe;</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> link_mode = std.builtin.LinkMode.Static;</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> is_test = <span class="tok-null">true</span>;</span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> single_threaded = <span class="tok-null">false</span>;</span>
<span class="line" id="L12"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> abi = std.Target.Abi.gnu;</span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> cpu: std.Target.Cpu = .{</span>
<span class="line" id="L14"> .arch = .x86_64,</span>
<span class="line" id="L15"> .model = &amp;std.Target.x86.cpu.x86_64,</span>
<span class="line" id="L16"> .features = std.Target.x86.featureSet(&amp;[_]std.Target.x86.Feature{</span>
<span class="line" id="L17"> .@&quot;64bit&quot;,</span>
<span class="line" id="L18"> .adx,</span>
<span class="line" id="L19"> .aes,</span>
<span class="line" id="L20"> .avx,</span>
<span class="line" id="L21"> .avx2,</span>
<span class="line" id="L22"> .bmi,</span>
<span class="line" id="L23"> .bmi2,</span>
<span class="line" id="L24"> .clflushopt,</span>
<span class="line" id="L25"> .clwb,</span>
<span class="line" id="L26"> .cmov,</span>
<span class="line" id="L27"> .cx16,</span>
<span class="line" id="L28"> .cx8,</span>
<span class="line" id="L29"> .f16c,</span>
<span class="line" id="L30"> .fma,</span>
<span class="line" id="L31"> .fsgsbase,</span>
<span class="line" id="L32"> .fxsr,</span>
<span class="line" id="L33"> .gfni,</span>
<span class="line" id="L34"> .idivq_to_divl,</span>
<span class="line" id="L35"> .invpcid,</span>
<span class="line" id="L36"> .lzcnt,</span>
<span class="line" id="L37"> .macrofusion,</span>
<span class="line" id="L38"> .mmx,</span>
<span class="line" id="L39"> .movbe,</span>
<span class="line" id="L40"> .movdir64b,</span>
<span class="line" id="L41"> .movdiri,</span>
<span class="line" id="L42"> .nopl,</span>
<span class="line" id="L43"> .pclmul,</span>
<span class="line" id="L44"> .pconfig,</span>
<span class="line" id="L45"> .pku,</span>
<span class="line" id="L46"> .popcnt,</span>
<span class="line" id="L47"> .prfchw,</span>
<span class="line" id="L48"> .ptwrite,</span>
<span class="line" id="L49"> .rdpid,</span>
<span class="line" id="L50"> .rdrnd,</span>
<span class="line" id="L51"> .rdseed,</span>
<span class="line" id="L52"> .sahf,</span>
<span class="line" id="L53"> .sha,</span>
<span class="line" id="L54"> .shstk,</span>
<span class="line" id="L55"> .slow_3ops_lea,</span>
<span class="line" id="L56"> .slow_incdec,</span>
<span class="line" id="L57"> .sse,</span>
<span class="line" id="L58"> .sse2,</span>
<span class="line" id="L59"> .sse3,</span>
<span class="line" id="L60"> .sse4_1,</span>
<span class="line" id="L61"> .sse4_2,</span>
<span class="line" id="L62"> .ssse3,</span>
<span class="line" id="L63"> .vaes,</span>
<span class="line" id="L64"> .vpclmulqdq,</span>
<span class="line" id="L65"> .vzeroupper,</span>
<span class="line" id="L66"> .waitpkg,</span>
<span class="line" id="L67"> .x87,</span>
<span class="line" id="L68"> .xsave,</span>
<span class="line" id="L69"> .xsavec,</span>
<span class="line" id="L70"> .xsaveopt,</span>
<span class="line" id="L71"> .xsaves,</span>
<span class="line" id="L72"> }),</span>
<span class="line" id="L73">};</span>
<span class="line" id="L74"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> os = std.Target.Os{</span>
<span class="line" id="L75"> .tag = .linux,</span>
<span class="line" id="L76"> .version_range = .{ .linux = .{</span>
<span class="line" id="L77"> .range = .{</span>
<span class="line" id="L78"> .min = .{</span>
<span class="line" id="L79"> .major = <span class="tok-number">5</span>,</span>
<span class="line" id="L80"> .minor = <span class="tok-number">15</span>,</span>
<span class="line" id="L81"> .patch = <span class="tok-number">0</span>,</span>
<span class="line" id="L82"> },</span>
<span class="line" id="L83"> .max = .{</span>
<span class="line" id="L84"> .major = <span class="tok-number">5</span>,</span>
<span class="line" id="L85"> .minor = <span class="tok-number">15</span>,</span>
<span class="line" id="L86"> .patch = <span class="tok-number">0</span>,</span>
<span class="line" id="L87"> },</span>
<span class="line" id="L88"> },</span>
<span class="line" id="L89"> .glibc = .{</span>
<span class="line" id="L90"> .major = <span class="tok-number">2</span>,</span>
<span class="line" id="L91"> .minor = <span class="tok-number">35</span>,</span>
<span class="line" id="L92"> .patch = <span class="tok-number">0</span>,</span>
<span class="line" id="L93"> },</span>
<span class="line" id="L94"> }},</span>
<span class="line" id="L95">};</span>
<span class="line" id="L96"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> target: std.Target = .{</span>
<span class="line" id="L97"> .cpu = cpu,</span>
<span class="line" id="L98"> .os = os,</span>
<span class="line" id="L99"> .abi = abi,</span>
<span class="line" id="L100"> .ofmt = object_format,</span>
<span class="line" id="L101"> .dynamic_linker = std.Target.DynamicLinker.init(<span class="tok-str">&quot;/lib64/ld-linux-x86-64.so.2&quot;</span>),</span>
<span class="line" id="L102">};</span>
<span class="line" id="L103"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> object_format = std.Target.ObjectFormat.elf;</span>
<span class="line" id="L104"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> mode = std.builtin.OptimizeMode.Debug;</span>
<span class="line" id="L105"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> link_libc = <span class="tok-null">false</span>;</span>
<span class="line" id="L106"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> link_libcpp = <span class="tok-null">false</span>;</span>
<span class="line" id="L107"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> have_error_return_tracing = <span class="tok-null">true</span>;</span>
<span class="line" id="L108"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> valgrind_support = <span class="tok-null">true</span>;</span>
<span class="line" id="L109"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sanitize_thread = <span class="tok-null">false</span>;</span>
<span class="line" id="L110"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> position_independent_code = <span class="tok-null">false</span>;</span>
<span class="line" id="L111"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> position_independent_executable = <span class="tok-null">false</span>;</span>
<span class="line" id="L112"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> strip_debug_info = <span class="tok-null">false</span>;</span>
<span class="line" id="L113"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> code_model = std.builtin.CodeModel.default;</span>
<span class="line" id="L114"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> omit_frame_pointer = <span class="tok-null">false</span>;</span>
<span class="line" id="L115"><span class="tok-kw">pub</span> <span class="tok-kw">var</span> test_functions: []<span class="tok-kw">const</span> std.builtin.TestFn = <span class="tok-null">undefined</span>; <span class="tok-comment">// overwritten later</span>
</span>
<span class="line" id="L116"></span>
</code></pre></body>
</html>

175
docs/src/main/Cell.zig.html Normal file
View file

@ -0,0 +1,175 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Cell.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Image.zig&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3">char: Character = .{},</span>
<span class="line" id="L4">style: Style = .{},</span>
<span class="line" id="L5">link: Hyperlink = .{},</span>
<span class="line" id="L6">image: ?Image.Placement = <span class="tok-null">null</span>,</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-comment">/// Segment is a contiguous run of text that has a constant style</span></span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Segment = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L10"> text: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L11"> style: Style = .{},</span>
<span class="line" id="L12"> link: Hyperlink = .{},</span>
<span class="line" id="L13">};</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Character = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L16"> grapheme: []<span class="tok-kw">const</span> <span class="tok-type">u8</span> = <span class="tok-str">&quot; &quot;</span>,</span>
<span class="line" id="L17"> <span class="tok-comment">/// width should only be provided when the application is sure the terminal</span></span>
<span class="line" id="L18"> <span class="tok-comment">/// will measure the same width. This can be ensure by using the gwidth method</span></span>
<span class="line" id="L19"> <span class="tok-comment">/// included in libvaxis. If width is 0, libvaxis will measure the glyph at</span></span>
<span class="line" id="L20"> <span class="tok-comment">/// render time</span></span>
<span class="line" id="L21"> width: <span class="tok-type">usize</span> = <span class="tok-number">1</span>,</span>
<span class="line" id="L22">};</span>
<span class="line" id="L23"></span>
<span class="line" id="L24"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Hyperlink = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L25"> uri: []<span class="tok-kw">const</span> <span class="tok-type">u8</span> = <span class="tok-str">&quot;&quot;</span>,</span>
<span class="line" id="L26"> <span class="tok-comment">/// ie &quot;id=app-1234&quot;</span></span>
<span class="line" id="L27"> params: []<span class="tok-kw">const</span> <span class="tok-type">u8</span> = <span class="tok-str">&quot;&quot;</span>,</span>
<span class="line" id="L28">};</span>
<span class="line" id="L29"></span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Style = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L31"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Underline = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L32"> off,</span>
<span class="line" id="L33"> single,</span>
<span class="line" id="L34"> double,</span>
<span class="line" id="L35"> curly,</span>
<span class="line" id="L36"> dotted,</span>
<span class="line" id="L37"> dashed,</span>
<span class="line" id="L38"> };</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"> fg: Color = .default,</span>
<span class="line" id="L41"> bg: Color = .default,</span>
<span class="line" id="L42"> ul: Color = .default,</span>
<span class="line" id="L43"> ul_style: Underline = .off,</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"> bold: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L46"> dim: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L47"> italic: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L48"> blink: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L49"> reverse: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L50"> invisible: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L51"> strikethrough: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L52">};</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Color = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L55"> default,</span>
<span class="line" id="L56"> index: <span class="tok-type">u8</span>,</span>
<span class="line" id="L57"> rgb: [<span class="tok-number">3</span>]<span class="tok-type">u8</span>,</span>
<span class="line" id="L58">};</span>
<span class="line" id="L59"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,142 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>GraphemeCache.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> testing = std.testing;</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> GraphemeCache = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-comment">/// the underlying storage for graphemes. Right now 8kb</span></span>
<span class="line" id="L7">buf: [<span class="tok-number">1024</span> * <span class="tok-number">8</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-comment">// the start index of the next grapheme</span>
</span>
<span class="line" id="L10">idx: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-comment">/// put a slice of bytes in the cache as a grapheme</span></span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">put</span>(self: *GraphemeCache, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) []<span class="tok-type">u8</span> {</span>
<span class="line" id="L14"> <span class="tok-comment">// reset the idx to 0 if we would overflow</span>
</span>
<span class="line" id="L15"> <span class="tok-kw">if</span> (self.idx + bytes.len &gt; self.buf.len) self.idx = <span class="tok-number">0</span>;</span>
<span class="line" id="L16"> <span class="tok-kw">defer</span> self.idx += bytes.len;</span>
<span class="line" id="L17"> <span class="tok-comment">// copy the grapheme to our storage</span>
</span>
<span class="line" id="L18"> <span class="tok-builtin">@memcpy</span>(self.buf[self.idx .. self.idx + bytes.len], bytes);</span>
<span class="line" id="L19"> <span class="tok-comment">// return the slice</span>
</span>
<span class="line" id="L20"> <span class="tok-kw">return</span> self.buf[self.idx .. self.idx + bytes.len];</span>
<span class="line" id="L21">}</span>
<span class="line" id="L22"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,191 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Image.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> fmt = std.fmt;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> math = std.math;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> testing = std.testing;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> base64 = std.base64.standard.Encoder;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> zigimg = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;zigimg&quot;</span>);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Window.zig&quot;</span>);</span>
<span class="line" id="L9"></span>
<span class="line" id="L10"><span class="tok-kw">const</span> log = std.log.scoped(.image);</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> transmit_opener = <span class="tok-str">&quot;\x1b_Gf=32,i={d},s={d},v={d},m={d};&quot;</span>;</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Source = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L17"> path: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L18"> mem: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L19">};</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Placement = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L22"> img_id: <span class="tok-type">u32</span>,</span>
<span class="line" id="L23"> z_index: <span class="tok-type">i32</span>,</span>
<span class="line" id="L24"> size: ?CellSize = <span class="tok-null">null</span>,</span>
<span class="line" id="L25">};</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CellSize = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L28"> rows: <span class="tok-type">usize</span>,</span>
<span class="line" id="L29"> cols: <span class="tok-type">usize</span>,</span>
<span class="line" id="L30">};</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"><span class="tok-comment">/// unique identifier for this image. This will be managed by the screen.</span></span>
<span class="line" id="L33">id: <span class="tok-type">u32</span>,</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"><span class="tok-comment">// width in pixels</span>
</span>
<span class="line" id="L36">width: <span class="tok-type">usize</span>,</span>
<span class="line" id="L37"><span class="tok-comment">// height in pixels</span>
</span>
<span class="line" id="L38">height: <span class="tok-type">usize</span>,</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">draw</span>(self: Image, win: Window, scale: <span class="tok-type">bool</span>, z_index: <span class="tok-type">i32</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L41"> <span class="tok-kw">const</span> p = Placement{</span>
<span class="line" id="L42"> .img_id = self.id,</span>
<span class="line" id="L43"> .z_index = z_index,</span>
<span class="line" id="L44"> .size = sz: {</span>
<span class="line" id="L45"> <span class="tok-kw">if</span> (!scale) <span class="tok-kw">break</span> :sz <span class="tok-null">null</span>;</span>
<span class="line" id="L46"> <span class="tok-kw">break</span> :sz CellSize{</span>
<span class="line" id="L47"> .rows = win.height,</span>
<span class="line" id="L48"> .cols = win.width,</span>
<span class="line" id="L49"> };</span>
<span class="line" id="L50"> },</span>
<span class="line" id="L51"> };</span>
<span class="line" id="L52"> win.writeCell(<span class="tok-number">0</span>, <span class="tok-number">0</span>, .{ .image = p });</span>
<span class="line" id="L53">}</span>
<span class="line" id="L54"></span>
<span class="line" id="L55"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">cellSize</span>(self: Image, win: Window) !CellSize {</span>
<span class="line" id="L56"> <span class="tok-comment">// cell geometry</span>
</span>
<span class="line" id="L57"> <span class="tok-kw">const</span> x_pix = win.screen.width_pix;</span>
<span class="line" id="L58"> <span class="tok-kw">const</span> y_pix = win.screen.height_pix;</span>
<span class="line" id="L59"> <span class="tok-kw">const</span> w = win.screen.width;</span>
<span class="line" id="L60"> <span class="tok-kw">const</span> h = win.screen.height;</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"> <span class="tok-kw">const</span> pix_per_col = <span class="tok-kw">try</span> std.math.divCeil(<span class="tok-type">usize</span>, x_pix, w);</span>
<span class="line" id="L63"> <span class="tok-kw">const</span> pix_per_row = <span class="tok-kw">try</span> std.math.divCeil(<span class="tok-type">usize</span>, y_pix, h);</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> <span class="tok-kw">const</span> cell_width = std.math.divCeil(<span class="tok-type">usize</span>, self.width, pix_per_col) <span class="tok-kw">catch</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L66"> <span class="tok-kw">const</span> cell_height = std.math.divCeil(<span class="tok-type">usize</span>, self.height, pix_per_row) <span class="tok-kw">catch</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L67"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L68"> .rows = cell_height,</span>
<span class="line" id="L69"> .cols = cell_width,</span>
<span class="line" id="L70"> };</span>
<span class="line" id="L71">}</span>
<span class="line" id="L72"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,215 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>InternalScreen.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> assert = std.debug.assert;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> Style = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>).Style;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Shape = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>).Shape;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> log = std.log.scoped(.internal_screen);</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> InternalScreen = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> InternalCell = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L12"> char: std.ArrayList(<span class="tok-type">u8</span>) = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L13"> style: Style = .{},</span>
<span class="line" id="L14"> uri: std.ArrayList(<span class="tok-type">u8</span>) = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L15"> uri_id: std.ArrayList(<span class="tok-type">u8</span>) = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L16"> <span class="tok-comment">// if we got skipped because of a wide character</span>
</span>
<span class="line" id="L17"> skipped: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eql</span>(self: InternalCell, cell: Cell) <span class="tok-type">bool</span> {</span>
<span class="line" id="L20"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, self.char.items, cell.char.grapheme) <span class="tok-kw">and</span></span>
<span class="line" id="L21"> std.meta.eql(self.style, cell.style) <span class="tok-kw">and</span></span>
<span class="line" id="L22"> std.mem.eql(<span class="tok-type">u8</span>, self.uri.items, cell.link.uri) <span class="tok-kw">and</span></span>
<span class="line" id="L23"> std.mem.eql(<span class="tok-type">u8</span>, self.uri_id.items, cell.link.params);</span>
<span class="line" id="L24"> }</span>
<span class="line" id="L25">};</span>
<span class="line" id="L26"></span>
<span class="line" id="L27">width: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L28">height: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L29"></span>
<span class="line" id="L30">buf: []InternalCell = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L31"></span>
<span class="line" id="L32">cursor_row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L33">cursor_col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L34">cursor_vis: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L35"></span>
<span class="line" id="L36">mouse_shape: Shape = .default,</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"><span class="tok-comment">/// sets each cell to the default cell</span></span>
<span class="line" id="L39"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(alloc: std.mem.Allocator, w: <span class="tok-type">usize</span>, h: <span class="tok-type">usize</span>) !InternalScreen {</span>
<span class="line" id="L40"> <span class="tok-kw">var</span> screen = InternalScreen{</span>
<span class="line" id="L41"> .buf = <span class="tok-kw">try</span> alloc.alloc(InternalCell, w * h),</span>
<span class="line" id="L42"> };</span>
<span class="line" id="L43"> <span class="tok-kw">for</span> (screen.buf, <span class="tok-number">0</span>..) |_, i| {</span>
<span class="line" id="L44"> screen.buf[i] = .{</span>
<span class="line" id="L45"> .char = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u8</span>).initCapacity(alloc, <span class="tok-number">1</span>),</span>
<span class="line" id="L46"> .uri = std.ArrayList(<span class="tok-type">u8</span>).init(alloc),</span>
<span class="line" id="L47"> .uri_id = std.ArrayList(<span class="tok-type">u8</span>).init(alloc),</span>
<span class="line" id="L48"> };</span>
<span class="line" id="L49"> }</span>
<span class="line" id="L50"> screen.width = w;</span>
<span class="line" id="L51"> screen.height = h;</span>
<span class="line" id="L52"> <span class="tok-kw">return</span> screen;</span>
<span class="line" id="L53">}</span>
<span class="line" id="L54"></span>
<span class="line" id="L55"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *InternalScreen, alloc: std.mem.Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L56"> <span class="tok-kw">for</span> (self.buf, <span class="tok-number">0</span>..) |_, i| {</span>
<span class="line" id="L57"> self.buf[i].char.deinit();</span>
<span class="line" id="L58"> self.buf[i].uri.deinit();</span>
<span class="line" id="L59"> self.buf[i].uri_id.deinit();</span>
<span class="line" id="L60"> }</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"> alloc.free(self.buf);</span>
<span class="line" id="L63">}</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"><span class="tok-comment">/// writes a cell to a location. 0 indexed</span></span>
<span class="line" id="L66"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeCell</span>(</span>
<span class="line" id="L67"> self: *InternalScreen,</span>
<span class="line" id="L68"> col: <span class="tok-type">usize</span>,</span>
<span class="line" id="L69"> row: <span class="tok-type">usize</span>,</span>
<span class="line" id="L70"> cell: Cell,</span>
<span class="line" id="L71">) <span class="tok-type">void</span> {</span>
<span class="line" id="L72"> <span class="tok-kw">if</span> (self.width &lt; col) {</span>
<span class="line" id="L73"> <span class="tok-comment">// column out of bounds</span>
</span>
<span class="line" id="L74"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L75"> }</span>
<span class="line" id="L76"> <span class="tok-kw">if</span> (self.height &lt; row) {</span>
<span class="line" id="L77"> <span class="tok-comment">// height out of bounds</span>
</span>
<span class="line" id="L78"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L79"> }</span>
<span class="line" id="L80"> <span class="tok-kw">const</span> i = (row * self.width) + col;</span>
<span class="line" id="L81"> assert(i &lt; self.buf.len);</span>
<span class="line" id="L82"> self.buf[i].char.clearRetainingCapacity();</span>
<span class="line" id="L83"> self.buf[i].char.appendSlice(cell.char.grapheme) <span class="tok-kw">catch</span> {</span>
<span class="line" id="L84"> log.warn(<span class="tok-str">&quot;couldn't write grapheme&quot;</span>, .{});</span>
<span class="line" id="L85"> };</span>
<span class="line" id="L86"> self.buf[i].uri.clearRetainingCapacity();</span>
<span class="line" id="L87"> self.buf[i].uri.appendSlice(cell.link.uri) <span class="tok-kw">catch</span> {</span>
<span class="line" id="L88"> log.warn(<span class="tok-str">&quot;couldn't write uri&quot;</span>, .{});</span>
<span class="line" id="L89"> };</span>
<span class="line" id="L90"> self.buf[i].uri.clearRetainingCapacity();</span>
<span class="line" id="L91"> self.buf[i].uri_id.appendSlice(cell.link.params) <span class="tok-kw">catch</span> {</span>
<span class="line" id="L92"> log.warn(<span class="tok-str">&quot;couldn't write uri_id&quot;</span>, .{});</span>
<span class="line" id="L93"> };</span>
<span class="line" id="L94"> self.buf[i].style = cell.style;</span>
<span class="line" id="L95">}</span>
<span class="line" id="L96"></span>
</code></pre></body>
</html>

427
docs/src/main/Key.zig.html Normal file
View file

@ -0,0 +1,427 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Key.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> testing = std.testing;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> ziglyph = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph&quot;</span>);</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> Key = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Modifiers = <span class="tok-kw">packed</span> <span class="tok-kw">struct</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L8"> shift: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L9"> alt: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L10"> ctrl: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L11"> super: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L12"> hyper: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L13"> meta: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L14"> caps_lock: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L15"> num_lock: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L16">};</span>
<span class="line" id="L17"></span>
<span class="line" id="L18"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> KittyFlags = <span class="tok-kw">packed</span> <span class="tok-kw">struct</span>(<span class="tok-type">u5</span>) {</span>
<span class="line" id="L19"> disambiguate: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L20"> report_events: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L21"> report_alternate_keys: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L22"> report_all_as_ctl_seqs: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L23"> report_text: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L24">};</span>
<span class="line" id="L25"></span>
<span class="line" id="L26"><span class="tok-comment">/// the unicode codepoint of the key event.</span></span>
<span class="line" id="L27">codepoint: <span class="tok-type">u21</span>,</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"><span class="tok-comment">/// the text generated from the key event. The underlying slice has a limited</span></span>
<span class="line" id="L30"><span class="tok-comment">/// lifetime. Vaxis maintains an internal ring buffer to temporarily store text.</span></span>
<span class="line" id="L31"><span class="tok-comment">/// If the application needs these values longer than the lifetime of the event</span></span>
<span class="line" id="L32"><span class="tok-comment">/// it must copy the data.</span></span>
<span class="line" id="L33">text: ?[]<span class="tok-kw">const</span> <span class="tok-type">u8</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"><span class="tok-comment">/// the shifted codepoint of this key event. This will only be present if the</span></span>
<span class="line" id="L36"><span class="tok-comment">/// Shift modifier was used to generate the event</span></span>
<span class="line" id="L37">shifted_codepoint: ?<span class="tok-type">u21</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"><span class="tok-comment">/// the key that would have been pressed on a standard keyboard layout. This is</span></span>
<span class="line" id="L40"><span class="tok-comment">/// useful for shortcut matching</span></span>
<span class="line" id="L41">base_layout_codepoint: ?<span class="tok-type">u21</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L42"></span>
<span class="line" id="L43">mods: Modifiers = .{},</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"><span class="tok-comment">// matches follows a loose matching algorithm for key matches.</span>
</span>
<span class="line" id="L46"><span class="tok-comment">// 1. If the codepoint and modifiers are exact matches</span>
</span>
<span class="line" id="L47"><span class="tok-comment">// 2. If the utf8 encoding of the codepoint matches the text</span>
</span>
<span class="line" id="L48"><span class="tok-comment">// 3. If there is a shifted codepoint and it matches after removing the shift</span>
</span>
<span class="line" id="L49"><span class="tok-comment">// modifier from self</span>
</span>
<span class="line" id="L50"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matches</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L51"> <span class="tok-comment">// rule 1</span>
</span>
<span class="line" id="L52"> <span class="tok-kw">if</span> (self.matchExact(cp, mods)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-comment">// rule 2</span>
</span>
<span class="line" id="L55"> <span class="tok-kw">if</span> (self.matchText(cp, mods)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L56"></span>
<span class="line" id="L57"> <span class="tok-comment">// rule 3</span>
</span>
<span class="line" id="L58"> <span class="tok-kw">if</span> (self.matchShiftedCodepoint(cp, mods)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L59"></span>
<span class="line" id="L60"> <span class="tok-comment">// rule 4</span>
</span>
<span class="line" id="L61"> <span class="tok-kw">if</span> (self.matchShiftedCodepoint(cp, mods)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L62"></span>
<span class="line" id="L63"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L64">}</span>
<span class="line" id="L65"></span>
<span class="line" id="L66"><span class="tok-comment">// matches base layout codes, useful for shortcut matching when an alternate key</span>
</span>
<span class="line" id="L67"><span class="tok-comment">// layout is used</span>
</span>
<span class="line" id="L68"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchShortcut</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L69"> <span class="tok-kw">if</span> (self.base_layout_codepoint == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L70"> <span class="tok-kw">return</span> cp == self.base_layout_codepoint.? <span class="tok-kw">and</span> std.meta.eql(self.mods, mods);</span>
<span class="line" id="L71">}</span>
<span class="line" id="L72"></span>
<span class="line" id="L73"><span class="tok-comment">// matches keys that aren't upper case versions when shifted. For example, shift</span>
</span>
<span class="line" id="L74"><span class="tok-comment">// + semicolon produces a colon. The key can be matched against shift +</span>
</span>
<span class="line" id="L75"><span class="tok-comment">// semicolon or just colon...or shift + ctrl + ; or just ctrl + :</span>
</span>
<span class="line" id="L76"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchShiftedCodepoint</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L77"> <span class="tok-kw">if</span> (self.shifted_codepoint == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L78"> <span class="tok-kw">if</span> (!self.mods.shift) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L79"> <span class="tok-kw">var</span> self_mods = self.mods;</span>
<span class="line" id="L80"> self_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L81"> <span class="tok-kw">return</span> cp == self.shifted_codepoint.? <span class="tok-kw">and</span> std.meta.eql(self_mods, mods);</span>
<span class="line" id="L82">}</span>
<span class="line" id="L83"></span>
<span class="line" id="L84"><span class="tok-comment">// matches when the utf8 encoding of the codepoint and relevant mods matches the</span>
</span>
<span class="line" id="L85"><span class="tok-comment">// text of the key. This function will consume Shift and Caps Lock when matching</span>
</span>
<span class="line" id="L86"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchText</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L87"> <span class="tok-comment">// return early if we have no text</span>
</span>
<span class="line" id="L88"> <span class="tok-kw">if</span> (self.text == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> <span class="tok-kw">var</span> self_mods = self.mods;</span>
<span class="line" id="L91"> <span class="tok-kw">var</span> arg_mods = mods;</span>
<span class="line" id="L92"> <span class="tok-kw">var</span> code = cp;</span>
<span class="line" id="L93"> <span class="tok-comment">// if the passed codepoint is upper, we consume all shift and caps mods for</span>
</span>
<span class="line" id="L94"> <span class="tok-comment">// checking</span>
</span>
<span class="line" id="L95"> <span class="tok-kw">if</span> (ziglyph.isUpper(cp)) {</span>
<span class="line" id="L96"> <span class="tok-comment">// consume mods</span>
</span>
<span class="line" id="L97"> self_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L98"> self_mods.caps_lock = <span class="tok-null">false</span>;</span>
<span class="line" id="L99"> arg_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L100"> arg_mods.caps_lock = <span class="tok-null">false</span>;</span>
<span class="line" id="L101"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (mods.shift <span class="tok-kw">or</span> mods.caps_lock) {</span>
<span class="line" id="L102"> <span class="tok-comment">// uppercase the cp and consume all mods</span>
</span>
<span class="line" id="L103"> code = ziglyph.toUpper(cp);</span>
<span class="line" id="L104"> self_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L105"> self_mods.caps_lock = <span class="tok-null">false</span>;</span>
<span class="line" id="L106"> arg_mods.shift = <span class="tok-null">false</span>;</span>
<span class="line" id="L107"> arg_mods.caps_lock = <span class="tok-null">false</span>;</span>
<span class="line" id="L108"> }</span>
<span class="line" id="L109"></span>
<span class="line" id="L110"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L111"> <span class="tok-kw">const</span> n = std.unicode.utf8Encode(cp, buf[<span class="tok-number">0</span>..]) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L112"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, self.text.?, buf[<span class="tok-number">0</span>..n]) <span class="tok-kw">and</span> std.meta.eql(self_mods, arg_mods);</span>
<span class="line" id="L113">}</span>
<span class="line" id="L114"></span>
<span class="line" id="L115"><span class="tok-comment">// The key must exactly match the codepoint and modifiers</span>
</span>
<span class="line" id="L116"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">matchExact</span>(self: Key, cp: <span class="tok-type">u21</span>, mods: Modifiers) <span class="tok-type">bool</span> {</span>
<span class="line" id="L117"> <span class="tok-kw">return</span> self.codepoint == cp <span class="tok-kw">and</span> std.meta.eql(self.mods, mods);</span>
<span class="line" id="L118">}</span>
<span class="line" id="L119"></span>
<span class="line" id="L120"><span class="tok-comment">// a few special keys that we encode as their actual ascii value</span>
</span>
<span class="line" id="L121"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> enter: <span class="tok-type">u21</span> = <span class="tok-number">0x0D</span>;</span>
<span class="line" id="L122"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> tab: <span class="tok-type">u21</span> = <span class="tok-number">0x09</span>;</span>
<span class="line" id="L123"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> escape: <span class="tok-type">u21</span> = <span class="tok-number">0x1B</span>;</span>
<span class="line" id="L124"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> space: <span class="tok-type">u21</span> = <span class="tok-number">0x20</span>;</span>
<span class="line" id="L125"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> backspace: <span class="tok-type">u21</span> = <span class="tok-number">0x7F</span>;</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"><span class="tok-comment">// multicodepoint is a key which generated text but cannot be expressed as a</span>
</span>
<span class="line" id="L128"><span class="tok-comment">// single codepoint. The value is the maximum unicode codepoint + 1</span>
</span>
<span class="line" id="L129"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> multicodepoint: <span class="tok-type">u21</span> = <span class="tok-number">1_114_112</span> + <span class="tok-number">1</span>;</span>
<span class="line" id="L130"></span>
<span class="line" id="L131"><span class="tok-comment">// kitty encodes these keys directly in the private use area. We reuse those</span>
</span>
<span class="line" id="L132"><span class="tok-comment">// mappings</span>
</span>
<span class="line" id="L133"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> insert: <span class="tok-type">u21</span> = <span class="tok-number">57348</span>;</span>
<span class="line" id="L134"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> delete: <span class="tok-type">u21</span> = <span class="tok-number">57349</span>;</span>
<span class="line" id="L135"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left: <span class="tok-type">u21</span> = <span class="tok-number">57350</span>;</span>
<span class="line" id="L136"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right: <span class="tok-type">u21</span> = <span class="tok-number">57351</span>;</span>
<span class="line" id="L137"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> up: <span class="tok-type">u21</span> = <span class="tok-number">57352</span>;</span>
<span class="line" id="L138"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> down: <span class="tok-type">u21</span> = <span class="tok-number">57353</span>;</span>
<span class="line" id="L139"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> page_up: <span class="tok-type">u21</span> = <span class="tok-number">57354</span>;</span>
<span class="line" id="L140"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> page_down: <span class="tok-type">u21</span> = <span class="tok-number">57355</span>;</span>
<span class="line" id="L141"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> home: <span class="tok-type">u21</span> = <span class="tok-number">57356</span>;</span>
<span class="line" id="L142"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> end: <span class="tok-type">u21</span> = <span class="tok-number">57357</span>;</span>
<span class="line" id="L143"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> caps_lock: <span class="tok-type">u21</span> = <span class="tok-number">57358</span>;</span>
<span class="line" id="L144"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> scroll_lock: <span class="tok-type">u21</span> = <span class="tok-number">57359</span>;</span>
<span class="line" id="L145"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> num_lock: <span class="tok-type">u21</span> = <span class="tok-number">57360</span>;</span>
<span class="line" id="L146"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> print_screen: <span class="tok-type">u21</span> = <span class="tok-number">57361</span>;</span>
<span class="line" id="L147"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> pause: <span class="tok-type">u21</span> = <span class="tok-number">57362</span>;</span>
<span class="line" id="L148"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> menu: <span class="tok-type">u21</span> = <span class="tok-number">57363</span>;</span>
<span class="line" id="L149"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f1: <span class="tok-type">u21</span> = <span class="tok-number">57364</span>;</span>
<span class="line" id="L150"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f2: <span class="tok-type">u21</span> = <span class="tok-number">57365</span>;</span>
<span class="line" id="L151"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f3: <span class="tok-type">u21</span> = <span class="tok-number">57366</span>;</span>
<span class="line" id="L152"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f4: <span class="tok-type">u21</span> = <span class="tok-number">57367</span>;</span>
<span class="line" id="L153"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f5: <span class="tok-type">u21</span> = <span class="tok-number">57368</span>;</span>
<span class="line" id="L154"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f6: <span class="tok-type">u21</span> = <span class="tok-number">57369</span>;</span>
<span class="line" id="L155"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f7: <span class="tok-type">u21</span> = <span class="tok-number">57370</span>;</span>
<span class="line" id="L156"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f8: <span class="tok-type">u21</span> = <span class="tok-number">57371</span>;</span>
<span class="line" id="L157"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f9: <span class="tok-type">u21</span> = <span class="tok-number">57372</span>;</span>
<span class="line" id="L158"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f10: <span class="tok-type">u21</span> = <span class="tok-number">57373</span>;</span>
<span class="line" id="L159"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f11: <span class="tok-type">u21</span> = <span class="tok-number">57374</span>;</span>
<span class="line" id="L160"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f12: <span class="tok-type">u21</span> = <span class="tok-number">57375</span>;</span>
<span class="line" id="L161"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f13: <span class="tok-type">u21</span> = <span class="tok-number">57376</span>;</span>
<span class="line" id="L162"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f14: <span class="tok-type">u21</span> = <span class="tok-number">57377</span>;</span>
<span class="line" id="L163"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f15: <span class="tok-type">u21</span> = <span class="tok-number">57378</span>;</span>
<span class="line" id="L164"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> @&quot;f16&quot;: <span class="tok-type">u21</span> = <span class="tok-number">57379</span>;</span>
<span class="line" id="L165"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f17: <span class="tok-type">u21</span> = <span class="tok-number">57380</span>;</span>
<span class="line" id="L166"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f18: <span class="tok-type">u21</span> = <span class="tok-number">57381</span>;</span>
<span class="line" id="L167"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f19: <span class="tok-type">u21</span> = <span class="tok-number">57382</span>;</span>
<span class="line" id="L168"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f20: <span class="tok-type">u21</span> = <span class="tok-number">57383</span>;</span>
<span class="line" id="L169"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f21: <span class="tok-type">u21</span> = <span class="tok-number">57384</span>;</span>
<span class="line" id="L170"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f22: <span class="tok-type">u21</span> = <span class="tok-number">57385</span>;</span>
<span class="line" id="L171"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f23: <span class="tok-type">u21</span> = <span class="tok-number">57386</span>;</span>
<span class="line" id="L172"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f24: <span class="tok-type">u21</span> = <span class="tok-number">57387</span>;</span>
<span class="line" id="L173"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f25: <span class="tok-type">u21</span> = <span class="tok-number">57388</span>;</span>
<span class="line" id="L174"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f26: <span class="tok-type">u21</span> = <span class="tok-number">57389</span>;</span>
<span class="line" id="L175"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f27: <span class="tok-type">u21</span> = <span class="tok-number">57390</span>;</span>
<span class="line" id="L176"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f28: <span class="tok-type">u21</span> = <span class="tok-number">57391</span>;</span>
<span class="line" id="L177"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f29: <span class="tok-type">u21</span> = <span class="tok-number">57392</span>;</span>
<span class="line" id="L178"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f30: <span class="tok-type">u21</span> = <span class="tok-number">57393</span>;</span>
<span class="line" id="L179"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f31: <span class="tok-type">u21</span> = <span class="tok-number">57394</span>;</span>
<span class="line" id="L180"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> @&quot;f32&quot;: <span class="tok-type">u21</span> = <span class="tok-number">57395</span>;</span>
<span class="line" id="L181"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f33: <span class="tok-type">u21</span> = <span class="tok-number">57396</span>;</span>
<span class="line" id="L182"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f34: <span class="tok-type">u21</span> = <span class="tok-number">57397</span>;</span>
<span class="line" id="L183"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> f35: <span class="tok-type">u21</span> = <span class="tok-number">57398</span>;</span>
<span class="line" id="L184"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_0: <span class="tok-type">u21</span> = <span class="tok-number">57399</span>;</span>
<span class="line" id="L185"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_1: <span class="tok-type">u21</span> = <span class="tok-number">57400</span>;</span>
<span class="line" id="L186"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_2: <span class="tok-type">u21</span> = <span class="tok-number">57401</span>;</span>
<span class="line" id="L187"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_3: <span class="tok-type">u21</span> = <span class="tok-number">57402</span>;</span>
<span class="line" id="L188"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_4: <span class="tok-type">u21</span> = <span class="tok-number">57403</span>;</span>
<span class="line" id="L189"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_5: <span class="tok-type">u21</span> = <span class="tok-number">57404</span>;</span>
<span class="line" id="L190"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_6: <span class="tok-type">u21</span> = <span class="tok-number">57405</span>;</span>
<span class="line" id="L191"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_7: <span class="tok-type">u21</span> = <span class="tok-number">57406</span>;</span>
<span class="line" id="L192"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_8: <span class="tok-type">u21</span> = <span class="tok-number">57407</span>;</span>
<span class="line" id="L193"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_9: <span class="tok-type">u21</span> = <span class="tok-number">57408</span>;</span>
<span class="line" id="L194"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_decimal: <span class="tok-type">u21</span> = <span class="tok-number">57409</span>;</span>
<span class="line" id="L195"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_divide: <span class="tok-type">u21</span> = <span class="tok-number">57410</span>;</span>
<span class="line" id="L196"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_multiply: <span class="tok-type">u21</span> = <span class="tok-number">57411</span>;</span>
<span class="line" id="L197"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_subtract: <span class="tok-type">u21</span> = <span class="tok-number">57412</span>;</span>
<span class="line" id="L198"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_add: <span class="tok-type">u21</span> = <span class="tok-number">57413</span>;</span>
<span class="line" id="L199"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_enter: <span class="tok-type">u21</span> = <span class="tok-number">57414</span>;</span>
<span class="line" id="L200"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_equal: <span class="tok-type">u21</span> = <span class="tok-number">57415</span>;</span>
<span class="line" id="L201"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_separator: <span class="tok-type">u21</span> = <span class="tok-number">57416</span>;</span>
<span class="line" id="L202"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_left: <span class="tok-type">u21</span> = <span class="tok-number">57417</span>;</span>
<span class="line" id="L203"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_right: <span class="tok-type">u21</span> = <span class="tok-number">57418</span>;</span>
<span class="line" id="L204"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_up: <span class="tok-type">u21</span> = <span class="tok-number">57419</span>;</span>
<span class="line" id="L205"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_down: <span class="tok-type">u21</span> = <span class="tok-number">57420</span>;</span>
<span class="line" id="L206"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_page_up: <span class="tok-type">u21</span> = <span class="tok-number">57421</span>;</span>
<span class="line" id="L207"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_page_down: <span class="tok-type">u21</span> = <span class="tok-number">57422</span>;</span>
<span class="line" id="L208"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_home: <span class="tok-type">u21</span> = <span class="tok-number">57423</span>;</span>
<span class="line" id="L209"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_end: <span class="tok-type">u21</span> = <span class="tok-number">57424</span>;</span>
<span class="line" id="L210"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_insert: <span class="tok-type">u21</span> = <span class="tok-number">57425</span>;</span>
<span class="line" id="L211"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_delete: <span class="tok-type">u21</span> = <span class="tok-number">57426</span>;</span>
<span class="line" id="L212"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kp_begin: <span class="tok-type">u21</span> = <span class="tok-number">57427</span>;</span>
<span class="line" id="L213"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_play: <span class="tok-type">u21</span> = <span class="tok-number">57428</span>;</span>
<span class="line" id="L214"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_pause: <span class="tok-type">u21</span> = <span class="tok-number">57429</span>;</span>
<span class="line" id="L215"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_play_pause: <span class="tok-type">u21</span> = <span class="tok-number">57430</span>;</span>
<span class="line" id="L216"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_reverse: <span class="tok-type">u21</span> = <span class="tok-number">57431</span>;</span>
<span class="line" id="L217"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_stop: <span class="tok-type">u21</span> = <span class="tok-number">57432</span>;</span>
<span class="line" id="L218"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_fast_forward: <span class="tok-type">u21</span> = <span class="tok-number">57433</span>;</span>
<span class="line" id="L219"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_rewind: <span class="tok-type">u21</span> = <span class="tok-number">57434</span>;</span>
<span class="line" id="L220"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_track_next: <span class="tok-type">u21</span> = <span class="tok-number">57435</span>;</span>
<span class="line" id="L221"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_track_previous: <span class="tok-type">u21</span> = <span class="tok-number">57436</span>;</span>
<span class="line" id="L222"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> media_record: <span class="tok-type">u21</span> = <span class="tok-number">57437</span>;</span>
<span class="line" id="L223"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> lower_volume: <span class="tok-type">u21</span> = <span class="tok-number">57438</span>;</span>
<span class="line" id="L224"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> raise_volume: <span class="tok-type">u21</span> = <span class="tok-number">57439</span>;</span>
<span class="line" id="L225"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> mute_volume: <span class="tok-type">u21</span> = <span class="tok-number">57440</span>;</span>
<span class="line" id="L226"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_shift: <span class="tok-type">u21</span> = <span class="tok-number">57441</span>;</span>
<span class="line" id="L227"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_control: <span class="tok-type">u21</span> = <span class="tok-number">57442</span>;</span>
<span class="line" id="L228"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_alt: <span class="tok-type">u21</span> = <span class="tok-number">57443</span>;</span>
<span class="line" id="L229"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_super: <span class="tok-type">u21</span> = <span class="tok-number">57444</span>;</span>
<span class="line" id="L230"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_hyper: <span class="tok-type">u21</span> = <span class="tok-number">57445</span>;</span>
<span class="line" id="L231"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> left_meta: <span class="tok-type">u21</span> = <span class="tok-number">57446</span>;</span>
<span class="line" id="L232"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_shift: <span class="tok-type">u21</span> = <span class="tok-number">57447</span>;</span>
<span class="line" id="L233"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_control: <span class="tok-type">u21</span> = <span class="tok-number">57448</span>;</span>
<span class="line" id="L234"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_alt: <span class="tok-type">u21</span> = <span class="tok-number">57449</span>;</span>
<span class="line" id="L235"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_super: <span class="tok-type">u21</span> = <span class="tok-number">57450</span>;</span>
<span class="line" id="L236"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_hyper: <span class="tok-type">u21</span> = <span class="tok-number">57451</span>;</span>
<span class="line" id="L237"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> right_meta: <span class="tok-type">u21</span> = <span class="tok-number">57452</span>;</span>
<span class="line" id="L238"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> iso_level_3_shift: <span class="tok-type">u21</span> = <span class="tok-number">57453</span>;</span>
<span class="line" id="L239"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> iso_level_5_shift: <span class="tok-type">u21</span> = <span class="tok-number">57454</span>;</span>
<span class="line" id="L240"></span>
<span class="line" id="L241"><span class="tok-kw">test</span> <span class="tok-str">&quot;matches 'a'&quot;</span> {</span>
<span class="line" id="L242"> <span class="tok-kw">const</span> key: Key = .{</span>
<span class="line" id="L243"> .codepoint = <span class="tok-str">'a'</span>,</span>
<span class="line" id="L244"> };</span>
<span class="line" id="L245"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">'a'</span>, .{}));</span>
<span class="line" id="L246">}</span>
<span class="line" id="L247"></span>
<span class="line" id="L248"><span class="tok-kw">test</span> <span class="tok-str">&quot;matches 'shift+a'&quot;</span> {</span>
<span class="line" id="L249"> <span class="tok-kw">const</span> key: Key = .{</span>
<span class="line" id="L250"> .codepoint = <span class="tok-str">'a'</span>,</span>
<span class="line" id="L251"> .mods = .{ .shift = <span class="tok-null">true</span> },</span>
<span class="line" id="L252"> .text = <span class="tok-str">&quot;A&quot;</span>,</span>
<span class="line" id="L253"> };</span>
<span class="line" id="L254"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">'a'</span>, .{ .shift = <span class="tok-null">true</span> }));</span>
<span class="line" id="L255"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">'A'</span>, .{}));</span>
<span class="line" id="L256"> <span class="tok-kw">try</span> testing.expect(!key.matches(<span class="tok-str">'A'</span>, .{ .ctrl = <span class="tok-null">true</span> }));</span>
<span class="line" id="L257">}</span>
<span class="line" id="L258"></span>
<span class="line" id="L259"><span class="tok-kw">test</span> <span class="tok-str">&quot;matches 'shift+tab'&quot;</span> {</span>
<span class="line" id="L260"> <span class="tok-kw">const</span> key: Key = .{</span>
<span class="line" id="L261"> .codepoint = Key.tab,</span>
<span class="line" id="L262"> .mods = .{ .shift = <span class="tok-null">true</span> },</span>
<span class="line" id="L263"> };</span>
<span class="line" id="L264"> <span class="tok-kw">try</span> testing.expect(key.matches(Key.tab, .{ .shift = <span class="tok-null">true</span> }));</span>
<span class="line" id="L265"> <span class="tok-kw">try</span> testing.expect(!key.matches(Key.tab, .{}));</span>
<span class="line" id="L266">}</span>
<span class="line" id="L267"></span>
<span class="line" id="L268"><span class="tok-kw">test</span> <span class="tok-str">&quot;matches 'shift+;'&quot;</span> {</span>
<span class="line" id="L269"> <span class="tok-kw">const</span> key: Key = .{</span>
<span class="line" id="L270"> .codepoint = <span class="tok-str">';'</span>,</span>
<span class="line" id="L271"> .shifted_codepoint = <span class="tok-str">':'</span>,</span>
<span class="line" id="L272"> .mods = .{ .shift = <span class="tok-null">true</span> },</span>
<span class="line" id="L273"> .text = <span class="tok-str">&quot;:&quot;</span>,</span>
<span class="line" id="L274"> };</span>
<span class="line" id="L275"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">';'</span>, .{ .shift = <span class="tok-null">true</span> }));</span>
<span class="line" id="L276"> <span class="tok-kw">try</span> testing.expect(key.matches(<span class="tok-str">':'</span>, .{}));</span>
<span class="line" id="L277"></span>
<span class="line" id="L278"> <span class="tok-kw">const</span> colon: Key = .{</span>
<span class="line" id="L279"> .codepoint = <span class="tok-str">':'</span>,</span>
<span class="line" id="L280"> .mods = .{},</span>
<span class="line" id="L281"> };</span>
<span class="line" id="L282"> <span class="tok-kw">try</span> testing.expect(colon.matches(<span class="tok-str">':'</span>, .{}));</span>
<span class="line" id="L283">}</span>
<span class="line" id="L284"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,163 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mouse.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">/// A mouse event</span></span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Mouse = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Shape = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L5"> default,</span>
<span class="line" id="L6"> text,</span>
<span class="line" id="L7"> pointer,</span>
<span class="line" id="L8"> help,</span>
<span class="line" id="L9"> progress,</span>
<span class="line" id="L10"> wait,</span>
<span class="line" id="L11"> @&quot;ew-resize&quot;,</span>
<span class="line" id="L12"> @&quot;ns-resize&quot;,</span>
<span class="line" id="L13"> cell,</span>
<span class="line" id="L14">};</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Button = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L17"> left,</span>
<span class="line" id="L18"> middle,</span>
<span class="line" id="L19"> right,</span>
<span class="line" id="L20"> none,</span>
<span class="line" id="L21"> wheel_up = <span class="tok-number">64</span>,</span>
<span class="line" id="L22"> wheel_down = <span class="tok-number">65</span>,</span>
<span class="line" id="L23"> button_8 = <span class="tok-number">128</span>,</span>
<span class="line" id="L24"> button_9 = <span class="tok-number">129</span>,</span>
<span class="line" id="L25"> button_10 = <span class="tok-number">130</span>,</span>
<span class="line" id="L26"> button_11 = <span class="tok-number">131</span>,</span>
<span class="line" id="L27">};</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Modifiers = <span class="tok-kw">packed</span> <span class="tok-kw">struct</span>(<span class="tok-type">u3</span>) {</span>
<span class="line" id="L30"> shift: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L31"> alt: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L32"> ctrl: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L33">};</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Type = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L36"> press,</span>
<span class="line" id="L37"> release,</span>
<span class="line" id="L38"> motion,</span>
<span class="line" id="L39"> drag,</span>
<span class="line" id="L40">};</span>
<span class="line" id="L41"></span>
<span class="line" id="L42">col: <span class="tok-type">usize</span>,</span>
<span class="line" id="L43">row: <span class="tok-type">usize</span>,</span>
<span class="line" id="L44">button: Button,</span>
<span class="line" id="L45">mods: Modifiers,</span>
<span class="line" id="L46"><span class="tok-type">type</span>: Type,</span>
<span class="line" id="L47"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,119 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Options.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">/// Runtime options</span></span>
<span class="line" id="L2"><span class="tok-kw">const</span> Options = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L3"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,181 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Screen.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> assert = std.debug.assert;</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Shape = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>).Shape;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Image.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> Winsize = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Tty.zig&quot;</span>).Winsize;</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> log = std.log.scoped(.screen);</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">const</span> Screen = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L12"></span>
<span class="line" id="L13">width: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L14">height: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L15"></span>
<span class="line" id="L16">width_pix: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L17">height_pix: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L18"></span>
<span class="line" id="L19">buf: []Cell = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L20"></span>
<span class="line" id="L21">cursor_row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L22">cursor_col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L23">cursor_vis: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"><span class="tok-comment">/// true when we measure cells with unicode</span></span>
<span class="line" id="L26">unicode: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L27"></span>
<span class="line" id="L28">mouse_shape: Shape = .default,</span>
<span class="line" id="L29"></span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(alloc: std.mem.Allocator, winsize: Winsize) !Screen {</span>
<span class="line" id="L31"> <span class="tok-kw">const</span> w = winsize.cols;</span>
<span class="line" id="L32"> <span class="tok-kw">const</span> h = winsize.rows;</span>
<span class="line" id="L33"> <span class="tok-kw">var</span> self = Screen{</span>
<span class="line" id="L34"> .buf = <span class="tok-kw">try</span> alloc.alloc(Cell, w * h),</span>
<span class="line" id="L35"> .width = w,</span>
<span class="line" id="L36"> .height = h,</span>
<span class="line" id="L37"> .width_pix = winsize.x_pixel,</span>
<span class="line" id="L38"> .height_pix = winsize.y_pixel,</span>
<span class="line" id="L39"> };</span>
<span class="line" id="L40"> <span class="tok-kw">for</span> (self.buf, <span class="tok-number">0</span>..) |_, i| {</span>
<span class="line" id="L41"> self.buf[i] = .{};</span>
<span class="line" id="L42"> }</span>
<span class="line" id="L43"> <span class="tok-kw">return</span> self;</span>
<span class="line" id="L44">}</span>
<span class="line" id="L45"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Screen, alloc: std.mem.Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L46"> alloc.free(self.buf);</span>
<span class="line" id="L47">}</span>
<span class="line" id="L48"></span>
<span class="line" id="L49"><span class="tok-comment">/// writes a cell to a location. 0 indexed</span></span>
<span class="line" id="L50"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeCell</span>(self: *Screen, col: <span class="tok-type">usize</span>, row: <span class="tok-type">usize</span>, cell: Cell) <span class="tok-type">void</span> {</span>
<span class="line" id="L51"> <span class="tok-kw">if</span> (self.width &lt; col) {</span>
<span class="line" id="L52"> <span class="tok-comment">// column out of bounds</span>
</span>
<span class="line" id="L53"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L54"> }</span>
<span class="line" id="L55"> <span class="tok-kw">if</span> (self.height &lt; row) {</span>
<span class="line" id="L56"> <span class="tok-comment">// height out of bounds</span>
</span>
<span class="line" id="L57"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L58"> }</span>
<span class="line" id="L59"> <span class="tok-kw">const</span> i = (row * self.width) + col;</span>
<span class="line" id="L60"> assert(i &lt; self.buf.len);</span>
<span class="line" id="L61"> self.buf[i] = cell;</span>
<span class="line" id="L62">}</span>
<span class="line" id="L63"></span>
</code></pre></body>
</html>

410
docs/src/main/Tty.zig.html Normal file
View file

@ -0,0 +1,410 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Tty.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> builtin = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;builtin&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> os = std.os;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Vaxis = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;vaxis.zig&quot;</span>).Vaxis;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Parser = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Parser.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> GraphemeCache = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;GraphemeCache.zig&quot;</span>);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">const</span> log = std.log.scoped(.tty);</span>
<span class="line" id="L9"></span>
<span class="line" id="L10"><span class="tok-kw">const</span> Tty = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-kw">const</span> Writer = std.io.Writer(os.fd_t, os.WriteError, os.write);</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> BufferedWriter = std.io.BufferedWriter(<span class="tok-number">4096</span>, Writer);</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-comment">/// the original state of the terminal, prior to calling makeRaw</span></span>
<span class="line" id="L17">termios: os.termios,</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"><span class="tok-comment">/// The file descriptor we are using for I/O</span></span>
<span class="line" id="L20">fd: os.fd_t,</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"><span class="tok-comment">/// the write end of a pipe to signal the tty should exit it's run loop</span></span>
<span class="line" id="L23">quit_fd: ?os.fd_t = <span class="tok-null">null</span>,</span>
<span class="line" id="L24"></span>
<span class="line" id="L25">buffered_writer: BufferedWriter,</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"><span class="tok-comment">/// initializes a Tty instance by opening /dev/tty and &quot;making it raw&quot;</span></span>
<span class="line" id="L28"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>() !Tty {</span>
<span class="line" id="L29"> <span class="tok-comment">// Open our tty</span>
</span>
<span class="line" id="L30"> <span class="tok-kw">const</span> fd = <span class="tok-kw">try</span> os.open(<span class="tok-str">&quot;/dev/tty&quot;</span>, .{ .ACCMODE = .RDWR }, <span class="tok-number">0</span>);</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"> <span class="tok-comment">// Set the termios of the tty</span>
</span>
<span class="line" id="L33"> <span class="tok-kw">const</span> termios = <span class="tok-kw">try</span> makeRaw(fd);</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"> <span class="tok-kw">return</span> Tty{</span>
<span class="line" id="L36"> .fd = fd,</span>
<span class="line" id="L37"> .termios = termios,</span>
<span class="line" id="L38"> .buffered_writer = std.io.bufferedWriter(Writer{ .context = fd }),</span>
<span class="line" id="L39"> };</span>
<span class="line" id="L40">}</span>
<span class="line" id="L41"></span>
<span class="line" id="L42"><span class="tok-comment">/// release resources associated with the Tty return it to it's original state</span></span>
<span class="line" id="L43"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Tty) <span class="tok-type">void</span> {</span>
<span class="line" id="L44"> os.tcsetattr(self.fd, .FLUSH, self.termios) <span class="tok-kw">catch</span> |err| {</span>
<span class="line" id="L45"> log.err(<span class="tok-str">&quot;couldn't restore terminal: {}&quot;</span>, .{err});</span>
<span class="line" id="L46"> };</span>
<span class="line" id="L47"> os.close(self.fd);</span>
<span class="line" id="L48">}</span>
<span class="line" id="L49"></span>
<span class="line" id="L50"><span class="tok-comment">/// stops the run loop</span></span>
<span class="line" id="L51"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">stop</span>(self: *Tty) <span class="tok-type">void</span> {</span>
<span class="line" id="L52"> <span class="tok-kw">if</span> (self.quit_fd) |fd| {</span>
<span class="line" id="L53"> _ = std.os.write(fd, <span class="tok-str">&quot;q&quot;</span>) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L54"> }</span>
<span class="line" id="L55">}</span>
<span class="line" id="L56"></span>
<span class="line" id="L57"><span class="tok-comment">/// read input from the tty</span></span>
<span class="line" id="L58"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">run</span>(</span>
<span class="line" id="L59"> self: *Tty,</span>
<span class="line" id="L60"> <span class="tok-kw">comptime</span> Event: <span class="tok-type">type</span>,</span>
<span class="line" id="L61"> vx: *Vaxis(Event),</span>
<span class="line" id="L62">) !<span class="tok-type">void</span> {</span>
<span class="line" id="L63"> <span class="tok-comment">// create a pipe so we can signal to exit the run loop</span>
</span>
<span class="line" id="L64"> <span class="tok-kw">const</span> pipe = <span class="tok-kw">try</span> os.pipe();</span>
<span class="line" id="L65"> <span class="tok-kw">defer</span> os.close(pipe[<span class="tok-number">0</span>]);</span>
<span class="line" id="L66"> <span class="tok-kw">defer</span> os.close(pipe[<span class="tok-number">1</span>]);</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"> <span class="tok-comment">// get our initial winsize</span>
</span>
<span class="line" id="L69"> <span class="tok-kw">const</span> winsize = <span class="tok-kw">try</span> getWinsize(self.fd);</span>
<span class="line" id="L70"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;winsize&quot;</span>)) {</span>
<span class="line" id="L71"> vx.postEvent(.{ .winsize = winsize });</span>
<span class="line" id="L72"> }</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"> <span class="tok-comment">// assign the write end of the pipe to our quit_fd</span>
</span>
<span class="line" id="L75"> self.quit_fd = pipe[<span class="tok-number">1</span>];</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"> <span class="tok-comment">// Build a winch handler. We need build this struct to get an anonymous</span>
</span>
<span class="line" id="L78"> <span class="tok-comment">// function which can post the winsize event</span>
</span>
<span class="line" id="L79"> <span class="tok-comment">// TODO: more signals, move this outside of this function?</span>
</span>
<span class="line" id="L80"> <span class="tok-kw">const</span> WinchHandler = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L81"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L82"></span>
<span class="line" id="L83"> <span class="tok-kw">var</span> vx_winch: *Vaxis(Event) = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L84"> <span class="tok-kw">var</span> fd: os.fd_t = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L85"></span>
<span class="line" id="L86"> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(vx_arg: *Vaxis(Event), fd_arg: os.fd_t) !<span class="tok-type">void</span> {</span>
<span class="line" id="L87"> vx_winch = vx_arg;</span>
<span class="line" id="L88"> fd = fd_arg;</span>
<span class="line" id="L89"> <span class="tok-kw">var</span> act = os.Sigaction{</span>
<span class="line" id="L90"> .handler = .{ .handler = Self.handleWinch },</span>
<span class="line" id="L91"> .mask = <span class="tok-kw">switch</span> (builtin.os.tag) {</span>
<span class="line" id="L92"> .macos =&gt; <span class="tok-number">0</span>,</span>
<span class="line" id="L93"> .linux =&gt; std.os.empty_sigset,</span>
<span class="line" id="L94"> <span class="tok-kw">else</span> =&gt; <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;os not supported&quot;</span>),</span>
<span class="line" id="L95"> },</span>
<span class="line" id="L96"> .flags = <span class="tok-number">0</span>,</span>
<span class="line" id="L97"> };</span>
<span class="line" id="L98"></span>
<span class="line" id="L99"> <span class="tok-kw">try</span> os.sigaction(os.SIG.WINCH, &amp;act, <span class="tok-null">null</span>);</span>
<span class="line" id="L100"> }</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"> <span class="tok-kw">fn</span> <span class="tok-fn">handleWinch</span>(_: <span class="tok-type">c_int</span>) <span class="tok-kw">callconv</span>(.C) <span class="tok-type">void</span> {</span>
<span class="line" id="L103"> <span class="tok-kw">const</span> ws = getWinsize(fd) <span class="tok-kw">catch</span> {</span>
<span class="line" id="L104"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L105"> };</span>
<span class="line" id="L106"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;winsize&quot;</span>)) {</span>
<span class="line" id="L107"> vx_winch.postEvent(.{ .winsize = ws });</span>
<span class="line" id="L108"> }</span>
<span class="line" id="L109"> }</span>
<span class="line" id="L110"> };</span>
<span class="line" id="L111"> <span class="tok-kw">try</span> WinchHandler.init(vx, self.fd);</span>
<span class="line" id="L112"></span>
<span class="line" id="L113"> <span class="tok-comment">// initialize a grapheme cache</span>
</span>
<span class="line" id="L114"> <span class="tok-kw">var</span> cache: GraphemeCache = .{};</span>
<span class="line" id="L115"></span>
<span class="line" id="L116"> <span class="tok-comment">// Set up fds for polling</span>
</span>
<span class="line" id="L117"> <span class="tok-kw">var</span> pollfds: [<span class="tok-number">2</span>]std.os.pollfd = .{</span>
<span class="line" id="L118"> .{ .fd = self.fd, .events = std.os.POLL.IN, .revents = <span class="tok-null">undefined</span> },</span>
<span class="line" id="L119"> .{ .fd = pipe[<span class="tok-number">0</span>], .events = std.os.POLL.IN, .revents = <span class="tok-null">undefined</span> },</span>
<span class="line" id="L120"> };</span>
<span class="line" id="L121"></span>
<span class="line" id="L122"> <span class="tok-kw">var</span> parser: Parser = .{};</span>
<span class="line" id="L123"></span>
<span class="line" id="L124"> <span class="tok-comment">// initialize the read buffer</span>
</span>
<span class="line" id="L125"> <span class="tok-kw">var</span> buf: [<span class="tok-number">1024</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L126"> <span class="tok-comment">// read loop</span>
</span>
<span class="line" id="L127"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L128"> _ = <span class="tok-kw">try</span> std.os.poll(&amp;pollfds, -<span class="tok-number">1</span>);</span>
<span class="line" id="L129"> <span class="tok-kw">if</span> (pollfds[<span class="tok-number">1</span>].revents &amp; std.os.POLL.IN != <span class="tok-number">0</span>) {</span>
<span class="line" id="L130"> log.info(<span class="tok-str">&quot;quitting read thread&quot;</span>, .{});</span>
<span class="line" id="L131"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L132"> }</span>
<span class="line" id="L133"></span>
<span class="line" id="L134"> <span class="tok-kw">const</span> n = <span class="tok-kw">try</span> os.read(self.fd, &amp;buf);</span>
<span class="line" id="L135"> <span class="tok-kw">var</span> start: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L136"> <span class="tok-kw">while</span> (start &lt; n) {</span>
<span class="line" id="L137"> <span class="tok-kw">const</span> result = <span class="tok-kw">try</span> parser.parse(buf[start..n]);</span>
<span class="line" id="L138"> start += result.n;</span>
<span class="line" id="L139"> <span class="tok-comment">// TODO: if we get 0 byte read, copy the remaining bytes to the</span>
</span>
<span class="line" id="L140"> <span class="tok-comment">// beginning of the buffer and read mmore? this should only happen</span>
</span>
<span class="line" id="L141"> <span class="tok-comment">// if we are in the middle of a grapheme at and filled our</span>
</span>
<span class="line" id="L142"> <span class="tok-comment">// buffer. Probably can happen on large pastes so needs to be</span>
</span>
<span class="line" id="L143"> <span class="tok-comment">// implemented but low priority</span>
</span>
<span class="line" id="L144"></span>
<span class="line" id="L145"> <span class="tok-kw">const</span> event = result.event <span class="tok-kw">orelse</span> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L146"> <span class="tok-kw">switch</span> (event) {</span>
<span class="line" id="L147"> .key_press =&gt; |key| {</span>
<span class="line" id="L148"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;key_press&quot;</span>)) {</span>
<span class="line" id="L149"> <span class="tok-comment">// HACK: yuck. there has to be a better way</span>
</span>
<span class="line" id="L150"> <span class="tok-kw">var</span> mut_key = key;</span>
<span class="line" id="L151"> <span class="tok-kw">if</span> (key.text) |text| {</span>
<span class="line" id="L152"> mut_key.text = cache.put(text);</span>
<span class="line" id="L153"> }</span>
<span class="line" id="L154"> vx.postEvent(.{ .key_press = mut_key });</span>
<span class="line" id="L155"> }</span>
<span class="line" id="L156"> },</span>
<span class="line" id="L157"> .mouse =&gt; |mouse| {</span>
<span class="line" id="L158"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;mouse&quot;</span>)) {</span>
<span class="line" id="L159"> vx.postEvent(.{ .mouse = mouse });</span>
<span class="line" id="L160"> }</span>
<span class="line" id="L161"> },</span>
<span class="line" id="L162"> .focus_in =&gt; {</span>
<span class="line" id="L163"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;focus_in&quot;</span>)) {</span>
<span class="line" id="L164"> vx.postEvent(.focus_in);</span>
<span class="line" id="L165"> }</span>
<span class="line" id="L166"> },</span>
<span class="line" id="L167"> .focus_out =&gt; {</span>
<span class="line" id="L168"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;focus_out&quot;</span>)) {</span>
<span class="line" id="L169"> vx.postEvent(.focus_out);</span>
<span class="line" id="L170"> }</span>
<span class="line" id="L171"> },</span>
<span class="line" id="L172"> .paste_start =&gt; {</span>
<span class="line" id="L173"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;paste_start&quot;</span>)) {</span>
<span class="line" id="L174"> vx.postEvent(.paste_start);</span>
<span class="line" id="L175"> }</span>
<span class="line" id="L176"> },</span>
<span class="line" id="L177"> .paste_end =&gt; {</span>
<span class="line" id="L178"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;paste_end&quot;</span>)) {</span>
<span class="line" id="L179"> vx.postEvent(.paste_end);</span>
<span class="line" id="L180"> }</span>
<span class="line" id="L181"> },</span>
<span class="line" id="L182"> .cap_kitty_keyboard =&gt; {</span>
<span class="line" id="L183"> log.info(<span class="tok-str">&quot;kitty keyboard capability detected&quot;</span>, .{});</span>
<span class="line" id="L184"> vx.caps.kitty_keyboard = <span class="tok-null">true</span>;</span>
<span class="line" id="L185"> },</span>
<span class="line" id="L186"> .cap_kitty_graphics =&gt; {</span>
<span class="line" id="L187"> <span class="tok-kw">if</span> (!vx.caps.kitty_graphics) {</span>
<span class="line" id="L188"> log.info(<span class="tok-str">&quot;kitty graphics capability detected&quot;</span>, .{});</span>
<span class="line" id="L189"> vx.caps.kitty_graphics = <span class="tok-null">true</span>;</span>
<span class="line" id="L190"> }</span>
<span class="line" id="L191"> },</span>
<span class="line" id="L192"> .cap_rgb =&gt; {</span>
<span class="line" id="L193"> log.info(<span class="tok-str">&quot;rgb capability detected&quot;</span>, .{});</span>
<span class="line" id="L194"> vx.caps.rgb = <span class="tok-null">true</span>;</span>
<span class="line" id="L195"> },</span>
<span class="line" id="L196"> .cap_unicode =&gt; {</span>
<span class="line" id="L197"> log.info(<span class="tok-str">&quot;unicode capability detected&quot;</span>, .{});</span>
<span class="line" id="L198"> vx.caps.unicode = <span class="tok-null">true</span>;</span>
<span class="line" id="L199"> vx.screen.unicode = <span class="tok-null">true</span>;</span>
<span class="line" id="L200"> },</span>
<span class="line" id="L201"> .cap_da1 =&gt; {</span>
<span class="line" id="L202"> std.Thread.Futex.wake(&amp;vx.query_futex, <span class="tok-number">10</span>);</span>
<span class="line" id="L203"> },</span>
<span class="line" id="L204"> }</span>
<span class="line" id="L205"> }</span>
<span class="line" id="L206"> }</span>
<span class="line" id="L207">}</span>
<span class="line" id="L208"></span>
<span class="line" id="L209"><span class="tok-comment">/// write to the tty. These writes are buffered and require calling flush to</span></span>
<span class="line" id="L210"><span class="tok-comment">/// flush writes to the tty</span></span>
<span class="line" id="L211"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: *Tty, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">usize</span> {</span>
<span class="line" id="L212"> <span class="tok-kw">return</span> self.buffered_writer.write(bytes);</span>
<span class="line" id="L213">}</span>
<span class="line" id="L214"></span>
<span class="line" id="L215"><span class="tok-comment">/// flushes the write buffer to the tty</span></span>
<span class="line" id="L216"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">flush</span>(self: *Tty) !<span class="tok-type">void</span> {</span>
<span class="line" id="L217"> <span class="tok-kw">try</span> self.buffered_writer.flush();</span>
<span class="line" id="L218">}</span>
<span class="line" id="L219"></span>
<span class="line" id="L220"><span class="tok-comment">/// makeRaw enters the raw state for the terminal.</span></span>
<span class="line" id="L221"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">makeRaw</span>(fd: os.fd_t) !os.termios {</span>
<span class="line" id="L222"> <span class="tok-kw">const</span> state = <span class="tok-kw">try</span> os.tcgetattr(fd);</span>
<span class="line" id="L223"> <span class="tok-kw">var</span> raw = state;</span>
<span class="line" id="L224"> <span class="tok-comment">// see termios(3)</span>
</span>
<span class="line" id="L225"> raw.iflag.IGNBRK = <span class="tok-null">false</span>;</span>
<span class="line" id="L226"> raw.iflag.BRKINT = <span class="tok-null">false</span>;</span>
<span class="line" id="L227"> raw.iflag.ISTRIP = <span class="tok-null">false</span>;</span>
<span class="line" id="L228"> raw.iflag.INLCR = <span class="tok-null">false</span>;</span>
<span class="line" id="L229"> raw.iflag.IGNCR = <span class="tok-null">false</span>;</span>
<span class="line" id="L230"> raw.iflag.ICRNL = <span class="tok-null">false</span>;</span>
<span class="line" id="L231"> raw.iflag.IXON = <span class="tok-null">false</span>;</span>
<span class="line" id="L232"></span>
<span class="line" id="L233"> raw.oflag.OPOST = <span class="tok-null">false</span>;</span>
<span class="line" id="L234"></span>
<span class="line" id="L235"> raw.lflag.ECHO = <span class="tok-null">false</span>;</span>
<span class="line" id="L236"> raw.lflag.ECHONL = <span class="tok-null">false</span>;</span>
<span class="line" id="L237"> raw.lflag.ICANON = <span class="tok-null">false</span>;</span>
<span class="line" id="L238"> raw.lflag.IEXTEN = <span class="tok-null">false</span>;</span>
<span class="line" id="L239"></span>
<span class="line" id="L240"> raw.cflag.CSIZE = .CS8;</span>
<span class="line" id="L241"> raw.cflag.PARENB = <span class="tok-null">false</span>;</span>
<span class="line" id="L242"></span>
<span class="line" id="L243"> raw.cc[<span class="tok-builtin">@intFromEnum</span>(std.posix.V.MIN)] = <span class="tok-number">1</span>;</span>
<span class="line" id="L244"> raw.cc[<span class="tok-builtin">@intFromEnum</span>(std.posix.V.TIME)] = <span class="tok-number">0</span>;</span>
<span class="line" id="L245"> <span class="tok-kw">try</span> os.tcsetattr(fd, .FLUSH, raw);</span>
<span class="line" id="L246"> <span class="tok-kw">return</span> state;</span>
<span class="line" id="L247">}</span>
<span class="line" id="L248"></span>
<span class="line" id="L249"><span class="tok-comment">/// The size of the terminal screen</span></span>
<span class="line" id="L250"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Winsize = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L251"> rows: <span class="tok-type">usize</span>,</span>
<span class="line" id="L252"> cols: <span class="tok-type">usize</span>,</span>
<span class="line" id="L253"> x_pixel: <span class="tok-type">usize</span>,</span>
<span class="line" id="L254"> y_pixel: <span class="tok-type">usize</span>,</span>
<span class="line" id="L255">};</span>
<span class="line" id="L256"></span>
<span class="line" id="L257"><span class="tok-kw">fn</span> <span class="tok-fn">getWinsize</span>(fd: os.fd_t) !Winsize {</span>
<span class="line" id="L258"> <span class="tok-kw">var</span> winsize = os.winsize{</span>
<span class="line" id="L259"> .ws_row = <span class="tok-number">0</span>,</span>
<span class="line" id="L260"> .ws_col = <span class="tok-number">0</span>,</span>
<span class="line" id="L261"> .ws_xpixel = <span class="tok-number">0</span>,</span>
<span class="line" id="L262"> .ws_ypixel = <span class="tok-number">0</span>,</span>
<span class="line" id="L263"> };</span>
<span class="line" id="L264"></span>
<span class="line" id="L265"> <span class="tok-kw">const</span> err = os.system.ioctl(fd, os.T.IOCGWINSZ, <span class="tok-builtin">@intFromPtr</span>(&amp;winsize));</span>
<span class="line" id="L266"> <span class="tok-kw">if</span> (os.errno(err) == .SUCCESS)</span>
<span class="line" id="L267"> <span class="tok-kw">return</span> Winsize{</span>
<span class="line" id="L268"> .rows = winsize.ws_row,</span>
<span class="line" id="L269"> .cols = winsize.ws_col,</span>
<span class="line" id="L270"> .x_pixel = winsize.ws_xpixel,</span>
<span class="line" id="L271"> .y_pixel = winsize.ws_ypixel,</span>
<span class="line" id="L272"> };</span>
<span class="line" id="L273"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.IoctlError;</span>
<span class="line" id="L274">}</span>
<span class="line" id="L275"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,338 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Window.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> ziglyph = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> WordIterator = ziglyph.WordIterator;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> GraphemeIterator = ziglyph.GraphemeIterator;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> Screen = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Screen.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> Segment = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>).Segment;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> gw = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;gwidth.zig&quot;</span>);</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">const</span> log = std.log.scoped(.window);</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Size = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L16"> expand,</span>
<span class="line" id="L17"> limit: <span class="tok-type">usize</span>,</span>
<span class="line" id="L18">};</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-comment">/// horizontal offset from the screen</span></span>
<span class="line" id="L21">x_off: <span class="tok-type">usize</span>,</span>
<span class="line" id="L22"><span class="tok-comment">/// vertical offset from the screen</span></span>
<span class="line" id="L23">y_off: <span class="tok-type">usize</span>,</span>
<span class="line" id="L24"><span class="tok-comment">/// width of the window. This can't be larger than the terminal screen</span></span>
<span class="line" id="L25">width: <span class="tok-type">usize</span>,</span>
<span class="line" id="L26"><span class="tok-comment">/// height of the window. This can't be larger than the terminal screen</span></span>
<span class="line" id="L27">height: <span class="tok-type">usize</span>,</span>
<span class="line" id="L28"></span>
<span class="line" id="L29">screen: *Screen,</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"><span class="tok-comment">/// Creates a new window with offset relative to parent and size clamped to the</span></span>
<span class="line" id="L32"><span class="tok-comment">/// parent's size. Windows do not retain a reference to their parent and are</span></span>
<span class="line" id="L33"><span class="tok-comment">/// unaware of resizes.</span></span>
<span class="line" id="L34"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">initChild</span>(</span>
<span class="line" id="L35"> self: Window,</span>
<span class="line" id="L36"> x_off: <span class="tok-type">usize</span>,</span>
<span class="line" id="L37"> y_off: <span class="tok-type">usize</span>,</span>
<span class="line" id="L38"> width: Size,</span>
<span class="line" id="L39"> height: Size,</span>
<span class="line" id="L40">) Window {</span>
<span class="line" id="L41"> <span class="tok-kw">const</span> resolved_width = <span class="tok-kw">switch</span> (width) {</span>
<span class="line" id="L42"> .expand =&gt; self.width - x_off,</span>
<span class="line" id="L43"> .limit =&gt; |w| blk: {</span>
<span class="line" id="L44"> <span class="tok-kw">if</span> (w + x_off &gt; self.width) {</span>
<span class="line" id="L45"> <span class="tok-kw">break</span> :blk self.width - x_off;</span>
<span class="line" id="L46"> }</span>
<span class="line" id="L47"> <span class="tok-kw">break</span> :blk w;</span>
<span class="line" id="L48"> },</span>
<span class="line" id="L49"> };</span>
<span class="line" id="L50"> <span class="tok-kw">const</span> resolved_height = <span class="tok-kw">switch</span> (height) {</span>
<span class="line" id="L51"> .expand =&gt; self.height - y_off,</span>
<span class="line" id="L52"> .limit =&gt; |h| blk: {</span>
<span class="line" id="L53"> <span class="tok-kw">if</span> (h + y_off &gt; self.height) {</span>
<span class="line" id="L54"> <span class="tok-kw">break</span> :blk self.height - y_off;</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56"> <span class="tok-kw">break</span> :blk h;</span>
<span class="line" id="L57"> },</span>
<span class="line" id="L58"> };</span>
<span class="line" id="L59"> <span class="tok-kw">return</span> Window{</span>
<span class="line" id="L60"> .x_off = x_off + self.x_off,</span>
<span class="line" id="L61"> .y_off = y_off + self.y_off,</span>
<span class="line" id="L62"> .width = resolved_width,</span>
<span class="line" id="L63"> .height = resolved_height,</span>
<span class="line" id="L64"> .screen = self.screen,</span>
<span class="line" id="L65"> };</span>
<span class="line" id="L66">}</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"><span class="tok-comment">/// writes a cell to the location in the window</span></span>
<span class="line" id="L69"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeCell</span>(self: Window, col: <span class="tok-type">usize</span>, row: <span class="tok-type">usize</span>, cell: Cell) <span class="tok-type">void</span> {</span>
<span class="line" id="L70"> <span class="tok-kw">if</span> (self.height == <span class="tok-number">0</span> <span class="tok-kw">or</span> self.width == <span class="tok-number">0</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L71"> <span class="tok-kw">if</span> (self.height &lt;= row <span class="tok-kw">or</span> self.width &lt;= col) <span class="tok-kw">return</span>;</span>
<span class="line" id="L72"> self.screen.writeCell(col + self.x_off, row + self.y_off, cell);</span>
<span class="line" id="L73">}</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"><span class="tok-comment">/// fills the window with the default cell</span></span>
<span class="line" id="L76"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">clear</span>(self: Window) <span class="tok-type">void</span> {</span>
<span class="line" id="L77"> self.fill(.{});</span>
<span class="line" id="L78">}</span>
<span class="line" id="L79"></span>
<span class="line" id="L80"><span class="tok-comment">/// returns the width of the grapheme. This depends on the terminal capabilities</span></span>
<span class="line" id="L81"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">gwidth</span>(self: Window, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L82"> <span class="tok-kw">const</span> m: gw.Method = <span class="tok-kw">if</span> (self.screen.unicode) .unicode <span class="tok-kw">else</span> .wcwidth;</span>
<span class="line" id="L83"> <span class="tok-kw">return</span> gw.gwidth(str, m) <span class="tok-kw">catch</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L84">}</span>
<span class="line" id="L85"></span>
<span class="line" id="L86"><span class="tok-comment">/// fills the window with the provided cell</span></span>
<span class="line" id="L87"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">fill</span>(self: Window, cell: Cell) <span class="tok-type">void</span> {</span>
<span class="line" id="L88"> <span class="tok-kw">var</span> row: <span class="tok-type">usize</span> = self.y_off;</span>
<span class="line" id="L89"> <span class="tok-kw">while</span> (row &lt; (self.height + self.y_off)) : (row += <span class="tok-number">1</span>) {</span>
<span class="line" id="L90"> <span class="tok-kw">var</span> col: <span class="tok-type">usize</span> = self.x_off;</span>
<span class="line" id="L91"> <span class="tok-kw">while</span> (col &lt; (self.width + self.x_off)) : (col += <span class="tok-number">1</span>) {</span>
<span class="line" id="L92"> self.screen.writeCell(col, row, cell);</span>
<span class="line" id="L93"> }</span>
<span class="line" id="L94"> }</span>
<span class="line" id="L95">}</span>
<span class="line" id="L96"></span>
<span class="line" id="L97"><span class="tok-comment">/// hide the cursor</span></span>
<span class="line" id="L98"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">hideCursor</span>(self: Window) <span class="tok-type">void</span> {</span>
<span class="line" id="L99"> self.screen.cursor_vis = <span class="tok-null">false</span>;</span>
<span class="line" id="L100">}</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"><span class="tok-comment">/// show the cursor at the given coordinates, 0 indexed</span></span>
<span class="line" id="L103"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">showCursor</span>(self: Window, col: <span class="tok-type">usize</span>, row: <span class="tok-type">usize</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L104"> <span class="tok-kw">if</span> (self.height == <span class="tok-number">0</span> <span class="tok-kw">or</span> self.width == <span class="tok-number">0</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L105"> <span class="tok-kw">if</span> (self.height &lt;= row <span class="tok-kw">or</span> self.width &lt;= col) <span class="tok-kw">return</span>;</span>
<span class="line" id="L106"> self.screen.cursor_vis = <span class="tok-null">true</span>;</span>
<span class="line" id="L107"> self.screen.cursor_row = row + self.y_off;</span>
<span class="line" id="L108"> self.screen.cursor_col = col + self.x_off;</span>
<span class="line" id="L109">}</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"><span class="tok-comment">/// prints text in the window with simple word wrapping.</span></span>
<span class="line" id="L112"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">wrap</span>(self: Window, segments: []Segment) !<span class="tok-type">void</span> {</span>
<span class="line" id="L113"> <span class="tok-comment">// pub fn wrap(self: Window, str: []const u8) !void {</span>
</span>
<span class="line" id="L114"> <span class="tok-kw">var</span> row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L115"> <span class="tok-kw">var</span> col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L116"> <span class="tok-kw">var</span> wrapped: <span class="tok-type">bool</span> = <span class="tok-null">false</span>;</span>
<span class="line" id="L117"> <span class="tok-kw">for</span> (segments) |segment| {</span>
<span class="line" id="L118"> <span class="tok-kw">var</span> word_iter = <span class="tok-kw">try</span> WordIterator.init(segment.text);</span>
<span class="line" id="L119"> <span class="tok-kw">while</span> (word_iter.next()) |word| {</span>
<span class="line" id="L120"> <span class="tok-comment">// break lines when we need</span>
</span>
<span class="line" id="L121"> <span class="tok-kw">if</span> (word.bytes[<span class="tok-number">0</span>] == <span class="tok-str">'\r'</span> <span class="tok-kw">or</span> word.bytes[<span class="tok-number">0</span>] == <span class="tok-str">'\n'</span>) {</span>
<span class="line" id="L122"> row += <span class="tok-number">1</span>;</span>
<span class="line" id="L123"> col = <span class="tok-number">0</span>;</span>
<span class="line" id="L124"> wrapped = <span class="tok-null">false</span>;</span>
<span class="line" id="L125"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L126"> }</span>
<span class="line" id="L127"> <span class="tok-comment">// break lines when we can't fit this word, and the word isn't longer</span>
</span>
<span class="line" id="L128"> <span class="tok-comment">// than our width</span>
</span>
<span class="line" id="L129"> <span class="tok-kw">const</span> word_width = self.gwidth(word.bytes);</span>
<span class="line" id="L130"> <span class="tok-kw">if</span> (word_width + col &gt;= self.width <span class="tok-kw">and</span> word_width &lt; self.width) {</span>
<span class="line" id="L131"> row += <span class="tok-number">1</span>;</span>
<span class="line" id="L132"> col = <span class="tok-number">0</span>;</span>
<span class="line" id="L133"> wrapped = <span class="tok-null">true</span>;</span>
<span class="line" id="L134"> }</span>
<span class="line" id="L135"> <span class="tok-comment">// don't print whitespace in the first column, unless we had a hard</span>
</span>
<span class="line" id="L136"> <span class="tok-comment">// break</span>
</span>
<span class="line" id="L137"> <span class="tok-kw">if</span> (col == <span class="tok-number">0</span> <span class="tok-kw">and</span> std.mem.eql(<span class="tok-type">u8</span>, word.bytes, <span class="tok-str">&quot; &quot;</span>) <span class="tok-kw">and</span> wrapped) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L138"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(word.bytes);</span>
<span class="line" id="L139"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L140"> <span class="tok-kw">if</span> (col &gt;= self.width) {</span>
<span class="line" id="L141"> row += <span class="tok-number">1</span>;</span>
<span class="line" id="L142"> col = <span class="tok-number">0</span>;</span>
<span class="line" id="L143"> wrapped = <span class="tok-null">true</span>;</span>
<span class="line" id="L144"> }</span>
<span class="line" id="L145"> <span class="tok-kw">const</span> s = grapheme.slice(word.bytes);</span>
<span class="line" id="L146"> <span class="tok-kw">const</span> w = self.gwidth(s);</span>
<span class="line" id="L147"> self.writeCell(col, row, .{</span>
<span class="line" id="L148"> .char = .{</span>
<span class="line" id="L149"> .grapheme = s,</span>
<span class="line" id="L150"> .width = w,</span>
<span class="line" id="L151"> },</span>
<span class="line" id="L152"> .style = segment.style,</span>
<span class="line" id="L153"> .link = segment.link,</span>
<span class="line" id="L154"> });</span>
<span class="line" id="L155"> col += w;</span>
<span class="line" id="L156"> }</span>
<span class="line" id="L157"> }</span>
<span class="line" id="L158"> }</span>
<span class="line" id="L159">}</span>
<span class="line" id="L160"></span>
<span class="line" id="L161"><span class="tok-kw">test</span> <span class="tok-str">&quot;Window size set&quot;</span> {</span>
<span class="line" id="L162"> <span class="tok-kw">var</span> parent = Window{</span>
<span class="line" id="L163"> .x_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L164"> .y_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L165"> .width = <span class="tok-number">20</span>,</span>
<span class="line" id="L166"> .height = <span class="tok-number">20</span>,</span>
<span class="line" id="L167"> .screen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L168"> };</span>
<span class="line" id="L169"></span>
<span class="line" id="L170"> <span class="tok-kw">const</span> child = parent.initChild(<span class="tok-number">1</span>, <span class="tok-number">1</span>, .expand, .expand);</span>
<span class="line" id="L171"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">19</span>, child.width);</span>
<span class="line" id="L172"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">19</span>, child.height);</span>
<span class="line" id="L173">}</span>
<span class="line" id="L174"></span>
<span class="line" id="L175"><span class="tok-kw">test</span> <span class="tok-str">&quot;Window size set too big&quot;</span> {</span>
<span class="line" id="L176"> <span class="tok-kw">var</span> parent = Window{</span>
<span class="line" id="L177"> .x_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L178"> .y_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L179"> .width = <span class="tok-number">20</span>,</span>
<span class="line" id="L180"> .height = <span class="tok-number">20</span>,</span>
<span class="line" id="L181"> .screen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L182"> };</span>
<span class="line" id="L183"></span>
<span class="line" id="L184"> <span class="tok-kw">const</span> child = parent.initChild(<span class="tok-number">0</span>, <span class="tok-number">0</span>, .{ .limit = <span class="tok-number">21</span> }, .{ .limit = <span class="tok-number">21</span> });</span>
<span class="line" id="L185"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">20</span>, child.width);</span>
<span class="line" id="L186"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">20</span>, child.height);</span>
<span class="line" id="L187">}</span>
<span class="line" id="L188"></span>
<span class="line" id="L189"><span class="tok-kw">test</span> <span class="tok-str">&quot;Window size set too big with offset&quot;</span> {</span>
<span class="line" id="L190"> <span class="tok-kw">var</span> parent = Window{</span>
<span class="line" id="L191"> .x_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L192"> .y_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L193"> .width = <span class="tok-number">20</span>,</span>
<span class="line" id="L194"> .height = <span class="tok-number">20</span>,</span>
<span class="line" id="L195"> .screen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L196"> };</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-kw">const</span> child = parent.initChild(<span class="tok-number">10</span>, <span class="tok-number">10</span>, .{ .limit = <span class="tok-number">21</span> }, .{ .limit = <span class="tok-number">21</span> });</span>
<span class="line" id="L199"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">10</span>, child.width);</span>
<span class="line" id="L200"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">10</span>, child.height);</span>
<span class="line" id="L201">}</span>
<span class="line" id="L202"></span>
<span class="line" id="L203"><span class="tok-kw">test</span> <span class="tok-str">&quot;Window size nested offsets&quot;</span> {</span>
<span class="line" id="L204"> <span class="tok-kw">var</span> parent = Window{</span>
<span class="line" id="L205"> .x_off = <span class="tok-number">1</span>,</span>
<span class="line" id="L206"> .y_off = <span class="tok-number">1</span>,</span>
<span class="line" id="L207"> .width = <span class="tok-number">20</span>,</span>
<span class="line" id="L208"> .height = <span class="tok-number">20</span>,</span>
<span class="line" id="L209"> .screen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L210"> };</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> <span class="tok-kw">const</span> child = parent.initChild(<span class="tok-number">10</span>, <span class="tok-number">10</span>, .{ .limit = <span class="tok-number">21</span> }, .{ .limit = <span class="tok-number">21</span> });</span>
<span class="line" id="L213"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">11</span>, child.x_off);</span>
<span class="line" id="L214"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">11</span>, child.y_off);</span>
<span class="line" id="L215">}</span>
<span class="line" id="L216"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,228 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ctlseqs.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Queries</span>
</span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> primary_device_attrs = <span class="tok-str">&quot;\x1b[c&quot;</span>;</span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> tertiary_device_attrs = <span class="tok-str">&quot;\x1b[=c&quot;</span>;</span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> xtversion = <span class="tok-str">&quot;\x1b[&gt;0q&quot;</span>;</span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> decrqm_focus = <span class="tok-str">&quot;\x1b[?1004$p&quot;</span>;</span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> decrqm_sync = <span class="tok-str">&quot;\x1b[?2026$p&quot;</span>;</span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> decrqm_unicode = <span class="tok-str">&quot;\x1b[?2027$p&quot;</span>;</span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> decrqm_color_theme = <span class="tok-str">&quot;\x1b[?2031$p&quot;</span>;</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> csi_u_query = <span class="tok-str">&quot;\x1b[?u&quot;</span>;</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kitty_graphics_query = <span class="tok-str">&quot;\x1b_Gi=1,a=q\x1b\\&quot;</span>;</span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sixel_geometry_query = <span class="tok-str">&quot;\x1b[?2;1;0S&quot;</span>;</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-comment">// mouse</span>
</span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> mouse_set = <span class="tok-str">&quot;\x1b[?1003;1004;1006h&quot;</span>;</span>
<span class="line" id="L15"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> mouse_reset = <span class="tok-str">&quot;\x1b[?1003;1004;1006l&quot;</span>;</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"><span class="tok-comment">// sync</span>
</span>
<span class="line" id="L18"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sync_set = <span class="tok-str">&quot;\x1b[?2026h&quot;</span>;</span>
<span class="line" id="L19"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sync_reset = <span class="tok-str">&quot;\x1b[?2026l&quot;</span>;</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-comment">// unicode</span>
</span>
<span class="line" id="L22"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> unicode_set = <span class="tok-str">&quot;\x1b[?2027h&quot;</span>;</span>
<span class="line" id="L23"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> unicode_reset = <span class="tok-str">&quot;\x1b[?2027l&quot;</span>;</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"><span class="tok-comment">// bracketed paste</span>
</span>
<span class="line" id="L26"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bp_set = <span class="tok-str">&quot;\x1b[?2004h&quot;</span>;</span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bp_reset = <span class="tok-str">&quot;\x1b[?2004l&quot;</span>;</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"><span class="tok-comment">// Key encoding</span>
</span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> csi_u_push = <span class="tok-str">&quot;\x1b[&gt;{d}u&quot;</span>;</span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> csi_u_pop = <span class="tok-str">&quot;\x1b[&lt;u&quot;</span>;</span>
<span class="line" id="L32"></span>
<span class="line" id="L33"><span class="tok-comment">// Cursor</span>
</span>
<span class="line" id="L34"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> home = <span class="tok-str">&quot;\x1b[H&quot;</span>;</span>
<span class="line" id="L35"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> cup = <span class="tok-str">&quot;\x1b[{d};{d}H&quot;</span>;</span>
<span class="line" id="L36"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> hide_cursor = <span class="tok-str">&quot;\x1b[?25l&quot;</span>;</span>
<span class="line" id="L37"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> show_cursor = <span class="tok-str">&quot;\x1b[?25h&quot;</span>;</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"><span class="tok-comment">// alt screen</span>
</span>
<span class="line" id="L40"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> smcup = <span class="tok-str">&quot;\x1b[?1049h&quot;</span>;</span>
<span class="line" id="L41"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> rmcup = <span class="tok-str">&quot;\x1b[?1049l&quot;</span>;</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"><span class="tok-comment">// sgr reset all</span>
</span>
<span class="line" id="L44"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sgr_reset = <span class="tok-str">&quot;\x1b[m&quot;</span>;</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"><span class="tok-comment">// colors</span>
</span>
<span class="line" id="L47"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_base = <span class="tok-str">&quot;\x1b[3{d}m&quot;</span>;</span>
<span class="line" id="L48"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_bright = <span class="tok-str">&quot;\x1b[9{d}m&quot;</span>;</span>
<span class="line" id="L49"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_base = <span class="tok-str">&quot;\x1b[4{d}m&quot;</span>;</span>
<span class="line" id="L50"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_bright = <span class="tok-str">&quot;\x1b[10{d}m&quot;</span>;</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_reset = <span class="tok-str">&quot;\x1b[39m&quot;</span>;</span>
<span class="line" id="L53"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_reset = <span class="tok-str">&quot;\x1b[49m&quot;</span>;</span>
<span class="line" id="L54"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_reset = <span class="tok-str">&quot;\x1b[59m&quot;</span>;</span>
<span class="line" id="L55"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_indexed = <span class="tok-str">&quot;\x1b[38:5:{d}m&quot;</span>;</span>
<span class="line" id="L56"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_indexed = <span class="tok-str">&quot;\x1b[48:5:{d}m&quot;</span>;</span>
<span class="line" id="L57"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_indexed = <span class="tok-str">&quot;\x1b[58:5:{d}m&quot;</span>;</span>
<span class="line" id="L58"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> fg_rgb = <span class="tok-str">&quot;\x1b[38:2:{d}:{d}:{d}m&quot;</span>;</span>
<span class="line" id="L59"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bg_rgb = <span class="tok-str">&quot;\x1b[48:2:{d}:{d}:{d}m&quot;</span>;</span>
<span class="line" id="L60"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_rgb = <span class="tok-str">&quot;\x1b[58:2:{d}:{d}:{d}m&quot;</span>;</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"><span class="tok-comment">// Underlines</span>
</span>
<span class="line" id="L63"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_off = <span class="tok-str">&quot;\x1b[24m&quot;</span>; <span class="tok-comment">// NOTE: this could be \x1b[4:0m but is not as widely supported</span>
</span>
<span class="line" id="L64"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_single = <span class="tok-str">&quot;\x1b[4m&quot;</span>;</span>
<span class="line" id="L65"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_double = <span class="tok-str">&quot;\x1b[4:2m&quot;</span>;</span>
<span class="line" id="L66"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_curly = <span class="tok-str">&quot;\x1b[4:3m&quot;</span>;</span>
<span class="line" id="L67"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_dotted = <span class="tok-str">&quot;\x1b[4:4m&quot;</span>;</span>
<span class="line" id="L68"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ul_dashed = <span class="tok-str">&quot;\x1b[4:5m&quot;</span>;</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"><span class="tok-comment">// Attributes</span>
</span>
<span class="line" id="L71"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bold_set = <span class="tok-str">&quot;\x1b[1m&quot;</span>;</span>
<span class="line" id="L72"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> dim_set = <span class="tok-str">&quot;\x1b[2m&quot;</span>;</span>
<span class="line" id="L73"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> italic_set = <span class="tok-str">&quot;\x1b[3m&quot;</span>;</span>
<span class="line" id="L74"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> blink_set = <span class="tok-str">&quot;\x1b[5m&quot;</span>;</span>
<span class="line" id="L75"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> reverse_set = <span class="tok-str">&quot;\x1b[7m&quot;</span>;</span>
<span class="line" id="L76"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> invisible_set = <span class="tok-str">&quot;\x1b[8m&quot;</span>;</span>
<span class="line" id="L77"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> strikethrough_set = <span class="tok-str">&quot;\x1b[9m&quot;</span>;</span>
<span class="line" id="L78"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bold_dim_reset = <span class="tok-str">&quot;\x1b[22m&quot;</span>;</span>
<span class="line" id="L79"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> italic_reset = <span class="tok-str">&quot;\x1b[23m&quot;</span>;</span>
<span class="line" id="L80"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> blink_reset = <span class="tok-str">&quot;\x1b[25m&quot;</span>;</span>
<span class="line" id="L81"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> reverse_reset = <span class="tok-str">&quot;\x1b[27m&quot;</span>;</span>
<span class="line" id="L82"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> invisible_reset = <span class="tok-str">&quot;\x1b[28m&quot;</span>;</span>
<span class="line" id="L83"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> strikethrough_reset = <span class="tok-str">&quot;\x1b[29m&quot;</span>;</span>
<span class="line" id="L84"></span>
<span class="line" id="L85"><span class="tok-comment">// OSC sequences</span>
</span>
<span class="line" id="L86"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc2_set_title = <span class="tok-str">&quot;\x1b]2;{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L87"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc8 = <span class="tok-str">&quot;\x1b]8;{s};{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L88"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc8_clear = <span class="tok-str">&quot;\x1b]8;;\x1b\\&quot;</span>;</span>
<span class="line" id="L89"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc9_notify = <span class="tok-str">&quot;\x1b]9;{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L90"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc777_notify = <span class="tok-str">&quot;\x1b]777;notify;{s};{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L91"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> osc22_mouse_shape = <span class="tok-str">&quot;\x1b]22;{s}\x1b\\&quot;</span>;</span>
<span class="line" id="L92"></span>
<span class="line" id="L93"><span class="tok-comment">// Kitty graphics</span>
</span>
<span class="line" id="L94"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kitty_graphics_clear = <span class="tok-str">&quot;\x1b_Ga=d\x1b\\&quot;</span>;</span>
<span class="line" id="L95"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kitty_graphics_place = <span class="tok-str">&quot;\x1b_Ga=p,i={d},z={d},C=1\x1b\\&quot;</span>;</span>
<span class="line" id="L96"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> kitty_graphics_scale = <span class="tok-str">&quot;\x1b_Ga=p,i={d},z={d},c={d},r={d},C=1\x1b\\&quot;</span>;</span>
<span class="line" id="L97"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,137 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>event.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Key = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Key.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Mouse = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>);</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-comment">/// The events that Vaxis emits internally</span></span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Event = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L6"> key_press: Key,</span>
<span class="line" id="L7"> mouse: Mouse,</span>
<span class="line" id="L8"> focus_in,</span>
<span class="line" id="L9"> focus_out,</span>
<span class="line" id="L10"> paste_start,</span>
<span class="line" id="L11"> paste_end,</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"> <span class="tok-comment">// these are delivered as discovered terminal capabilities</span>
</span>
<span class="line" id="L14"> cap_kitty_keyboard,</span>
<span class="line" id="L15"> cap_kitty_graphics,</span>
<span class="line" id="L16"> cap_rgb,</span>
<span class="line" id="L17"> cap_unicode,</span>
<span class="line" id="L18"> cap_da1,</span>
<span class="line" id="L19">};</span>
<span class="line" id="L20"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,185 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>gwidth.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> unicode = std.unicode;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> testing = std.testing;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> ziglyph = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph&quot;</span>);</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-comment">/// the method to use when calculating the width of a grapheme</span></span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Method = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L8"> unicode,</span>
<span class="line" id="L9"> wcwidth,</span>
<span class="line" id="L10"> no_zwj,</span>
<span class="line" id="L11">};</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-comment">/// returns the width of the provided string, as measured by the method chosen</span></span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">gwidth</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, method: Method) !<span class="tok-type">usize</span> {</span>
<span class="line" id="L15"> <span class="tok-kw">switch</span> (method) {</span>
<span class="line" id="L16"> .unicode =&gt; {</span>
<span class="line" id="L17"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> ziglyph.display_width.strWidth(str, .half);</span>
<span class="line" id="L18"> },</span>
<span class="line" id="L19"> .wcwidth =&gt; {</span>
<span class="line" id="L20"> <span class="tok-kw">var</span> total: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L21"> <span class="tok-kw">const</span> utf8 = <span class="tok-kw">try</span> unicode.Utf8View.init(str);</span>
<span class="line" id="L22"> <span class="tok-kw">var</span> iter = utf8.iterator();</span>
<span class="line" id="L23"></span>
<span class="line" id="L24"> <span class="tok-kw">while</span> (iter.nextCodepoint()) |cp| {</span>
<span class="line" id="L25"> <span class="tok-kw">const</span> w = ziglyph.display_width.codePointWidth(cp, .half);</span>
<span class="line" id="L26"> <span class="tok-kw">if</span> (w &lt; <span class="tok-number">0</span>) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L27"> total += <span class="tok-builtin">@intCast</span>(w);</span>
<span class="line" id="L28"> }</span>
<span class="line" id="L29"> <span class="tok-kw">return</span> total;</span>
<span class="line" id="L30"> },</span>
<span class="line" id="L31"> .no_zwj =&gt; {</span>
<span class="line" id="L32"> <span class="tok-kw">var</span> out: [<span class="tok-number">256</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L33"> <span class="tok-kw">if</span> (str.len &gt; out.len) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.OutOfMemory;</span>
<span class="line" id="L34"> <span class="tok-kw">const</span> n = std.mem.replace(<span class="tok-type">u8</span>, str, <span class="tok-str">&quot;\u{200D}&quot;</span>, <span class="tok-str">&quot;&quot;</span>, &amp;out);</span>
<span class="line" id="L35"> <span class="tok-kw">return</span> gwidth(out[<span class="tok-number">0</span>..n], .unicode);</span>
<span class="line" id="L36"> },</span>
<span class="line" id="L37"> }</span>
<span class="line" id="L38">}</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: a&quot;</span> {</span>
<span class="line" id="L41"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">1</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;a&quot;</span>, .unicode));</span>
<span class="line" id="L42"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">1</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;a&quot;</span>, .wcwidth));</span>
<span class="line" id="L43"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">1</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;a&quot;</span>, .no_zwj));</span>
<span class="line" id="L44">}</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: emoji with ZWJ&quot;</span> {</span>
<span class="line" id="L47"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👩‍🚀&quot;</span>, .unicode));</span>
<span class="line" id="L48"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">4</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👩‍🚀&quot;</span>, .wcwidth));</span>
<span class="line" id="L49"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">4</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👩‍🚀&quot;</span>, .no_zwj));</span>
<span class="line" id="L50">}</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: emoji with VS16 selector&quot;</span> {</span>
<span class="line" id="L53"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;\xE2\x9D\xA4\xEF\xB8\x8F&quot;</span>, .unicode));</span>
<span class="line" id="L54"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">1</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;\xE2\x9D\xA4\xEF\xB8\x8F&quot;</span>, .wcwidth));</span>
<span class="line" id="L55"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;\xE2\x9D\xA4\xEF\xB8\x8F&quot;</span>, .no_zwj));</span>
<span class="line" id="L56">}</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: emoji with skin tone selector&quot;</span> {</span>
<span class="line" id="L59"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👋🏿&quot;</span>, .unicode));</span>
<span class="line" id="L60"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">4</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👋🏿&quot;</span>, .wcwidth));</span>
<span class="line" id="L61"> <span class="tok-kw">try</span> testing.expectEqual(<span class="tok-number">2</span>, <span class="tok-kw">try</span> gwidth(<span class="tok-str">&quot;👋🏿&quot;</span>, .no_zwj));</span>
<span class="line" id="L62">}</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"><span class="tok-kw">test</span> <span class="tok-str">&quot;gwidth: invalid string&quot;</span> {</span>
<span class="line" id="L65"> <span class="tok-kw">try</span> testing.expectError(<span class="tok-kw">error</span>.InvalidUtf8, gwidth(<span class="tok-str">&quot;\xc3\x28&quot;</span>, .unicode));</span>
<span class="line" id="L66"> <span class="tok-kw">try</span> testing.expectError(<span class="tok-kw">error</span>.InvalidUtf8, gwidth(<span class="tok-str">&quot;\xc3\x28&quot;</span>, .wcwidth));</span>
<span class="line" id="L67"> <span class="tok-kw">try</span> testing.expectError(<span class="tok-kw">error</span>.InvalidUtf8, gwidth(<span class="tok-str">&quot;\xc3\x28&quot;</span>, .no_zwj));</span>
<span class="line" id="L68">}</span>
<span class="line" id="L69"></span>
</code></pre></body>
</html>

139
docs/src/main/main.zig.html Normal file
View file

@ -0,0 +1,139 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>main.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Vaxis = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;vaxis.zig&quot;</span>).Vaxis;</span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Options = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Options.zig&quot;</span>);</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Key = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Key.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Style = Cell.Style;</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Image.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Mouse = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>);</span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Winsize = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Tty.zig&quot;</span>).Winsize;</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> widgets = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets.zig&quot;</span>);</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-comment">/// Initialize a Vaxis application.</span></span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(<span class="tok-kw">comptime</span> Event: <span class="tok-type">type</span>, opts: Options) !Vaxis(Event) {</span>
<span class="line" id="L17"> <span class="tok-kw">return</span> Vaxis(Event).init(opts);</span>
<span class="line" id="L18">}</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-kw">test</span> {</span>
<span class="line" id="L21"> std.testing.refAllDecls(<span class="tok-builtin">@This</span>());</span>
<span class="line" id="L22">}</span>
<span class="line" id="L23"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,244 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>queue.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> assert = std.debug.assert;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> atomic = std.atomic;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Futex = std.Thread.Futex;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> log = std.log.scoped(.queue);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-comment">/// Thread safe. Fixed size. Blocking push and pop.</span></span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">Queue</span>(</span>
<span class="line" id="L10"> <span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>,</span>
<span class="line" id="L11"> <span class="tok-kw">comptime</span> size: <span class="tok-type">usize</span>,</span>
<span class="line" id="L12">) <span class="tok-type">type</span> {</span>
<span class="line" id="L13"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L14"> buf: [size]T = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"> read_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L17"> write_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"> mutex: std.Thread.Mutex = .{},</span>
<span class="line" id="L20"> <span class="tok-comment">// blocks when the buffer is full or empty</span>
</span>
<span class="line" id="L21"> futex: atomic.Value(<span class="tok-type">u32</span>) = atomic.Value(<span class="tok-type">u32</span>).init(<span class="tok-number">0</span>),</span>
<span class="line" id="L22"></span>
<span class="line" id="L23"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"> <span class="tok-comment">/// pop an item from the queue. Blocks until an item is available</span></span>
<span class="line" id="L26"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pop</span>(self: *Self) T {</span>
<span class="line" id="L27"> self.mutex.lock();</span>
<span class="line" id="L28"> <span class="tok-kw">defer</span> self.mutex.unlock();</span>
<span class="line" id="L29"> <span class="tok-kw">if</span> (self.isEmpty()) {</span>
<span class="line" id="L30"> <span class="tok-comment">// If we don't have any items, we unlock and wait</span>
</span>
<span class="line" id="L31"> self.mutex.unlock();</span>
<span class="line" id="L32"> Futex.wait(&amp;self.futex, <span class="tok-number">0</span>);</span>
<span class="line" id="L33"> <span class="tok-comment">// regain our lock</span>
</span>
<span class="line" id="L34"> self.mutex.lock();</span>
<span class="line" id="L35"> }</span>
<span class="line" id="L36"> <span class="tok-kw">if</span> (self.isFull()) {</span>
<span class="line" id="L37"> <span class="tok-comment">// If we are full, wake up the push</span>
</span>
<span class="line" id="L38"> Futex.wake(&amp;self.futex, <span class="tok-number">1</span>);</span>
<span class="line" id="L39"> }</span>
<span class="line" id="L40"> <span class="tok-kw">const</span> i = self.read_index;</span>
<span class="line" id="L41"> self.read_index += <span class="tok-number">1</span>;</span>
<span class="line" id="L42"> self.read_index = self.read_index % self.buf.len;</span>
<span class="line" id="L43"> <span class="tok-kw">return</span> self.buf[i];</span>
<span class="line" id="L44"> }</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> <span class="tok-comment">/// push an item into the queue. Blocks until the item has been put in</span></span>
<span class="line" id="L47"> <span class="tok-comment">/// the queue</span></span>
<span class="line" id="L48"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">push</span>(self: *Self, item: T) <span class="tok-type">void</span> {</span>
<span class="line" id="L49"> self.mutex.lock();</span>
<span class="line" id="L50"> <span class="tok-kw">defer</span> self.mutex.unlock();</span>
<span class="line" id="L51"> <span class="tok-kw">if</span> (self.isFull()) {</span>
<span class="line" id="L52"> self.mutex.unlock();</span>
<span class="line" id="L53"> Futex.wait(&amp;self.futex, <span class="tok-number">0</span>);</span>
<span class="line" id="L54"> self.mutex.lock();</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56"> <span class="tok-kw">if</span> (self.isEmpty()) {</span>
<span class="line" id="L57"> Futex.wake(&amp;self.futex, <span class="tok-number">1</span>);</span>
<span class="line" id="L58"> }</span>
<span class="line" id="L59"> <span class="tok-kw">const</span> i = self.write_index;</span>
<span class="line" id="L60"> self.write_index += <span class="tok-number">1</span>;</span>
<span class="line" id="L61"> self.write_index = self.write_index % self.buf.len;</span>
<span class="line" id="L62"> self.buf[i] = item;</span>
<span class="line" id="L63"> }</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> <span class="tok-comment">/// push an item into the queue. Returns true when the item was</span></span>
<span class="line" id="L66"> <span class="tok-comment">/// successfully placed in the queue</span></span>
<span class="line" id="L67"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">tryPush</span>(self: *Self, item: T) <span class="tok-type">bool</span> {</span>
<span class="line" id="L68"> self.mutex.lock();</span>
<span class="line" id="L69"> <span class="tok-kw">if</span> (self.isFull()) {</span>
<span class="line" id="L70"> self.mutex.unlock();</span>
<span class="line" id="L71"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L72"> }</span>
<span class="line" id="L73"> self.mutex.unlock();</span>
<span class="line" id="L74"> self.push(item);</span>
<span class="line" id="L75"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L76"> }</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> <span class="tok-comment">/// pop an item from the queue. Returns null when no item is available</span></span>
<span class="line" id="L79"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">tryPop</span>(self: *Self) ?T {</span>
<span class="line" id="L80"> self.mutex.lock();</span>
<span class="line" id="L81"> <span class="tok-kw">if</span> (self.isEmpty()) {</span>
<span class="line" id="L82"> self.mutex.unlock();</span>
<span class="line" id="L83"> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L84"> }</span>
<span class="line" id="L85"> self.mutex.unlock();</span>
<span class="line" id="L86"> <span class="tok-kw">return</span> self.pop();</span>
<span class="line" id="L87"> }</span>
<span class="line" id="L88"></span>
<span class="line" id="L89"> <span class="tok-comment">/// Returns `true` if the ring buffer is empty and `false` otherwise.</span></span>
<span class="line" id="L90"> <span class="tok-kw">fn</span> <span class="tok-fn">isEmpty</span>(self: Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L91"> <span class="tok-kw">return</span> self.write_index == self.read_index;</span>
<span class="line" id="L92"> }</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"> <span class="tok-comment">/// Returns `true` if the ring buffer is full and `false` otherwise.</span></span>
<span class="line" id="L95"> <span class="tok-kw">fn</span> <span class="tok-fn">isFull</span>(self: Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L96"> <span class="tok-kw">return</span> self.mask2(self.write_index + self.buf.len) == self.read_index;</span>
<span class="line" id="L97"> }</span>
<span class="line" id="L98"></span>
<span class="line" id="L99"> <span class="tok-comment">/// Returns the length</span></span>
<span class="line" id="L100"> <span class="tok-kw">fn</span> <span class="tok-fn">len</span>(self: Self) <span class="tok-type">usize</span> {</span>
<span class="line" id="L101"> <span class="tok-kw">const</span> wrap_offset = <span class="tok-number">2</span> * self.buf.len * <span class="tok-builtin">@intFromBool</span>(self.write_index &lt; self.read_index);</span>
<span class="line" id="L102"> <span class="tok-kw">const</span> adjusted_write_index = self.write_index + wrap_offset;</span>
<span class="line" id="L103"> <span class="tok-kw">return</span> adjusted_write_index - self.read_index;</span>
<span class="line" id="L104"> }</span>
<span class="line" id="L105"></span>
<span class="line" id="L106"> <span class="tok-comment">/// Returns `index` modulo the length of the backing slice.</span></span>
<span class="line" id="L107"> <span class="tok-kw">fn</span> <span class="tok-fn">mask</span>(self: Self, index: <span class="tok-type">usize</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L108"> <span class="tok-kw">return</span> index % self.buf.len;</span>
<span class="line" id="L109"> }</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"> <span class="tok-comment">/// Returns `index` modulo twice the length of the backing slice.</span></span>
<span class="line" id="L112"> <span class="tok-kw">fn</span> <span class="tok-fn">mask2</span>(self: Self, index: <span class="tok-type">usize</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L113"> <span class="tok-kw">return</span> index % (<span class="tok-number">2</span> * self.buf.len);</span>
<span class="line" id="L114"> }</span>
<span class="line" id="L115"> };</span>
<span class="line" id="L116">}</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"><span class="tok-kw">test</span> <span class="tok-str">&quot;Queue: simple push / pop&quot;</span> {</span>
<span class="line" id="L119"> <span class="tok-kw">var</span> queue: Queue(<span class="tok-type">u8</span>, <span class="tok-number">16</span>) = .{};</span>
<span class="line" id="L120"> queue.push(<span class="tok-number">1</span>);</span>
<span class="line" id="L121"> <span class="tok-kw">const</span> pop = queue.pop();</span>
<span class="line" id="L122"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-number">1</span>, pop);</span>
<span class="line" id="L123">}</span>
<span class="line" id="L124"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,851 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>vaxis.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> atomic = std.atomic;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> base64 = std.base64.standard.Encoder;</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> Queue = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;queue.zig&quot;</span>).Queue;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> ctlseqs = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ctlseqs.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> Tty = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Tty.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> Winsize = Tty.Winsize;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> Key = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Key.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> Screen = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Screen.zig&quot;</span>);</span>
<span class="line" id="L11"><span class="tok-kw">const</span> InternalScreen = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;InternalScreen.zig&quot;</span>);</span>
<span class="line" id="L12"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Window.zig&quot;</span>);</span>
<span class="line" id="L13"><span class="tok-kw">const</span> Options = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Options.zig&quot;</span>);</span>
<span class="line" id="L14"><span class="tok-kw">const</span> Style = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>).Style;</span>
<span class="line" id="L15"><span class="tok-kw">const</span> Hyperlink = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Cell.zig&quot;</span>).Hyperlink;</span>
<span class="line" id="L16"><span class="tok-kw">const</span> gwidth = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;gwidth.zig&quot;</span>);</span>
<span class="line" id="L17"><span class="tok-kw">const</span> Shape = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Mouse.zig&quot;</span>).Shape;</span>
<span class="line" id="L18"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Image.zig&quot;</span>);</span>
<span class="line" id="L19"><span class="tok-kw">const</span> zigimg = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;zigimg&quot;</span>);</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-comment">/// Vaxis is the entrypoint for a Vaxis application. The provided type T should</span></span>
<span class="line" id="L22"><span class="tok-comment">/// be a tagged union which contains all of the events the application will</span></span>
<span class="line" id="L23"><span class="tok-comment">/// handle. Vaxis will look for the following fields on the union and, if</span></span>
<span class="line" id="L24"><span class="tok-comment">/// found, emit them via the &quot;nextEvent&quot; method</span></span>
<span class="line" id="L25"><span class="tok-comment">///</span></span>
<span class="line" id="L26"><span class="tok-comment">/// The following events are available:</span></span>
<span class="line" id="L27"><span class="tok-comment">/// - `key_press: Key`, for key press events</span></span>
<span class="line" id="L28"><span class="tok-comment">/// - `winsize: Winsize`, for resize events. Must call app.resize when receiving</span></span>
<span class="line" id="L29"><span class="tok-comment">/// this event</span></span>
<span class="line" id="L30"><span class="tok-comment">/// - `focus_in` and `focus_out` for focus events</span></span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">Vaxis</span>(<span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L32"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L33"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"> <span class="tok-kw">const</span> log = std.log.scoped(.vaxis);</span>
<span class="line" id="L36"></span>
<span class="line" id="L37"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Event = T;</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Capabilities = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L40"> kitty_keyboard: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L41"> kitty_graphics: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L42"> rgb: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L43"> unicode: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L44"> };</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> <span class="tok-comment">/// the event queue for Vaxis</span></span>
<span class="line" id="L47"> <span class="tok-comment">//</span>
</span>
<span class="line" id="L48"> <span class="tok-comment">// TODO: is 512 ok?</span>
</span>
<span class="line" id="L49"> queue: Queue(T, <span class="tok-number">512</span>),</span>
<span class="line" id="L50"></span>
<span class="line" id="L51"> tty: ?Tty,</span>
<span class="line" id="L52"></span>
<span class="line" id="L53"> <span class="tok-comment">/// the screen we write to</span></span>
<span class="line" id="L54"> screen: Screen,</span>
<span class="line" id="L55"> <span class="tok-comment">/// The last screen we drew. We keep this so we can efficiently update on</span></span>
<span class="line" id="L56"> <span class="tok-comment">/// the next render</span></span>
<span class="line" id="L57"> screen_last: InternalScreen = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L58"></span>
<span class="line" id="L59"> state: <span class="tok-kw">struct</span> {</span>
<span class="line" id="L60"> <span class="tok-comment">/// if we are in the alt screen</span></span>
<span class="line" id="L61"> alt_screen: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L62"> <span class="tok-comment">/// if we have entered kitty keyboard</span></span>
<span class="line" id="L63"> kitty_keyboard: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L64"> bracketed_paste: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L65"> mouse: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L66"> } = .{},</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"> caps: Capabilities = .{},</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-comment">/// if we should redraw the entire screen on the next render</span></span>
<span class="line" id="L71"> refresh: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L72"></span>
<span class="line" id="L73"> <span class="tok-comment">/// blocks the main thread until a DA1 query has been received, or the</span></span>
<span class="line" id="L74"> <span class="tok-comment">/// futex times out</span></span>
<span class="line" id="L75"> query_futex: atomic.Value(<span class="tok-type">u32</span>) = atomic.Value(<span class="tok-type">u32</span>).init(<span class="tok-number">0</span>),</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"> <span class="tok-comment">// images</span>
</span>
<span class="line" id="L78"> next_img_id: <span class="tok-type">u32</span> = <span class="tok-number">1</span>,</span>
<span class="line" id="L79"></span>
<span class="line" id="L80"> <span class="tok-comment">// statistics</span>
</span>
<span class="line" id="L81"> renders: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L82"> render_dur: <span class="tok-type">i128</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L83"></span>
<span class="line" id="L84"> <span class="tok-comment">/// Initialize Vaxis with runtime options</span></span>
<span class="line" id="L85"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(_: Options) !Self {</span>
<span class="line" id="L86"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L87"> .queue = .{},</span>
<span class="line" id="L88"> .tty = <span class="tok-null">null</span>,</span>
<span class="line" id="L89"> .screen = .{},</span>
<span class="line" id="L90"> .screen_last = .{},</span>
<span class="line" id="L91"> };</span>
<span class="line" id="L92"> }</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"> <span class="tok-comment">/// Resets the terminal to it's original state. If an allocator is</span></span>
<span class="line" id="L95"> <span class="tok-comment">/// passed, this will free resources associated with Vaxis. This is left as an</span></span>
<span class="line" id="L96"> <span class="tok-comment">/// optional so applications can choose to not free resources when the</span></span>
<span class="line" id="L97"> <span class="tok-comment">/// application will be exiting anyways</span></span>
<span class="line" id="L98"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self, alloc: ?std.mem.Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L99"> <span class="tok-kw">if</span> (self.tty) |_| {</span>
<span class="line" id="L100"> <span class="tok-kw">var</span> tty = &amp;self.tty.?;</span>
<span class="line" id="L101"> <span class="tok-kw">if</span> (self.state.kitty_keyboard) {</span>
<span class="line" id="L102"> _ = tty.write(ctlseqs.csi_u_pop) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L103"> }</span>
<span class="line" id="L104"> <span class="tok-kw">if</span> (self.state.mouse) {</span>
<span class="line" id="L105"> _ = tty.write(ctlseqs.mouse_reset) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L106"> }</span>
<span class="line" id="L107"> <span class="tok-kw">if</span> (self.state.bracketed_paste) {</span>
<span class="line" id="L108"> _ = tty.write(ctlseqs.bp_reset) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L109"> }</span>
<span class="line" id="L110"> <span class="tok-kw">if</span> (self.state.alt_screen) {</span>
<span class="line" id="L111"> _ = tty.write(ctlseqs.rmcup) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L112"> }</span>
<span class="line" id="L113"> tty.flush() <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L114"> tty.deinit();</span>
<span class="line" id="L115"> }</span>
<span class="line" id="L116"> <span class="tok-kw">if</span> (alloc) |a| {</span>
<span class="line" id="L117"> self.screen.deinit(a);</span>
<span class="line" id="L118"> self.screen_last.deinit(a);</span>
<span class="line" id="L119"> }</span>
<span class="line" id="L120"> <span class="tok-kw">if</span> (self.renders &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L121"> <span class="tok-kw">const</span> tpr = <span class="tok-builtin">@divTrunc</span>(self.render_dur, self.renders);</span>
<span class="line" id="L122"> log.info(<span class="tok-str">&quot;total renders = {d}&quot;</span>, .{self.renders});</span>
<span class="line" id="L123"> log.info(<span class="tok-str">&quot;microseconds per render = {d}&quot;</span>, .{tpr});</span>
<span class="line" id="L124"> }</span>
<span class="line" id="L125"> }</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"> <span class="tok-comment">/// spawns the input thread to start listening to the tty for input</span></span>
<span class="line" id="L128"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">startReadThread</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L129"> self.tty = <span class="tok-kw">try</span> Tty.init();</span>
<span class="line" id="L130"> <span class="tok-comment">// run our tty read loop in it's own thread</span>
</span>
<span class="line" id="L131"> <span class="tok-kw">const</span> read_thread = <span class="tok-kw">try</span> std.Thread.spawn(.{}, Tty.run, .{ &amp;self.tty.?, T, self });</span>
<span class="line" id="L132"> <span class="tok-kw">try</span> read_thread.setName(<span class="tok-str">&quot;tty&quot;</span>);</span>
<span class="line" id="L133"> }</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"> <span class="tok-comment">/// stops reading from the tty</span></span>
<span class="line" id="L136"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">stopReadThread</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L137"> <span class="tok-kw">if</span> (self.tty) |_| {</span>
<span class="line" id="L138"> <span class="tok-kw">var</span> tty = &amp;self.tty.?;</span>
<span class="line" id="L139"> tty.stop();</span>
<span class="line" id="L140"> }</span>
<span class="line" id="L141"> }</span>
<span class="line" id="L142"></span>
<span class="line" id="L143"> <span class="tok-comment">/// returns the next available event, blocking until one is available</span></span>
<span class="line" id="L144"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">nextEvent</span>(self: *Self) T {</span>
<span class="line" id="L145"> <span class="tok-kw">return</span> self.queue.pop();</span>
<span class="line" id="L146"> }</span>
<span class="line" id="L147"></span>
<span class="line" id="L148"> <span class="tok-comment">/// posts an event into the event queue. Will block if there is not</span></span>
<span class="line" id="L149"> <span class="tok-comment">/// capacity for the event</span></span>
<span class="line" id="L150"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">postEvent</span>(self: *Self, event: T) <span class="tok-type">void</span> {</span>
<span class="line" id="L151"> self.queue.push(event);</span>
<span class="line" id="L152"> }</span>
<span class="line" id="L153"></span>
<span class="line" id="L154"> <span class="tok-comment">/// resize allocates a slice of cells equal to the number of cells</span></span>
<span class="line" id="L155"> <span class="tok-comment">/// required to display the screen (ie width x height). Any previous screen is</span></span>
<span class="line" id="L156"> <span class="tok-comment">/// freed when resizing</span></span>
<span class="line" id="L157"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">resize</span>(self: *Self, alloc: std.mem.Allocator, winsize: Winsize) !<span class="tok-type">void</span> {</span>
<span class="line" id="L158"> log.debug(<span class="tok-str">&quot;resizing screen: width={d} height={d}&quot;</span>, .{ winsize.cols, winsize.rows });</span>
<span class="line" id="L159"> self.screen.deinit(alloc);</span>
<span class="line" id="L160"> self.screen = <span class="tok-kw">try</span> Screen.init(alloc, winsize);</span>
<span class="line" id="L161"> self.screen.unicode = self.caps.unicode;</span>
<span class="line" id="L162"> <span class="tok-comment">// try self.screen.int(alloc, winsize.cols, winsize.rows);</span>
</span>
<span class="line" id="L163"> <span class="tok-comment">// we only init our current screen. This has the effect of redrawing</span>
</span>
<span class="line" id="L164"> <span class="tok-comment">// every cell</span>
</span>
<span class="line" id="L165"> self.screen_last.deinit(alloc);</span>
<span class="line" id="L166"> self.screen_last = <span class="tok-kw">try</span> InternalScreen.init(alloc, winsize.cols, winsize.rows);</span>
<span class="line" id="L167"> <span class="tok-comment">// try self.screen_last.resize(alloc, winsize.cols, winsize.rows);</span>
</span>
<span class="line" id="L168"> }</span>
<span class="line" id="L169"></span>
<span class="line" id="L170"> <span class="tok-comment">/// returns a Window comprising of the entire terminal screen</span></span>
<span class="line" id="L171"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">window</span>(self: *Self) Window {</span>
<span class="line" id="L172"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L173"> .x_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L174"> .y_off = <span class="tok-number">0</span>,</span>
<span class="line" id="L175"> .width = self.screen.width,</span>
<span class="line" id="L176"> .height = self.screen.height,</span>
<span class="line" id="L177"> .screen = &amp;self.screen,</span>
<span class="line" id="L178"> };</span>
<span class="line" id="L179"> }</span>
<span class="line" id="L180"></span>
<span class="line" id="L181"> <span class="tok-comment">/// enter the alternate screen. The alternate screen will automatically</span></span>
<span class="line" id="L182"> <span class="tok-comment">/// be exited if calling deinit while in the alt screen</span></span>
<span class="line" id="L183"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">enterAltScreen</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L184"> <span class="tok-kw">if</span> (self.state.alt_screen) <span class="tok-kw">return</span>;</span>
<span class="line" id="L185"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L186"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.smcup);</span>
<span class="line" id="L187"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L188"> self.state.alt_screen = <span class="tok-null">true</span>;</span>
<span class="line" id="L189"> }</span>
<span class="line" id="L190"></span>
<span class="line" id="L191"> <span class="tok-comment">/// exit the alternate screen</span></span>
<span class="line" id="L192"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">exitAltScreen</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L193"> <span class="tok-kw">if</span> (!self.state.alt_screen) <span class="tok-kw">return</span>;</span>
<span class="line" id="L194"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L195"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.rmcup);</span>
<span class="line" id="L196"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L197"> self.state.alt_screen = <span class="tok-null">false</span>;</span>
<span class="line" id="L198"> }</span>
<span class="line" id="L199"></span>
<span class="line" id="L200"> <span class="tok-comment">/// write queries to the terminal to determine capabilities. Individual</span></span>
<span class="line" id="L201"> <span class="tok-comment">/// capabilities will be delivered to the client and possibly intercepted by</span></span>
<span class="line" id="L202"> <span class="tok-comment">/// Vaxis to enable features</span></span>
<span class="line" id="L203"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">queryTerminal</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L204"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L205"></span>
<span class="line" id="L206"> <span class="tok-kw">const</span> colorterm = std.os.getenv(<span class="tok-str">&quot;COLORTERM&quot;</span>) <span class="tok-kw">orelse</span> <span class="tok-str">&quot;&quot;</span>;</span>
<span class="line" id="L207"> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, colorterm, <span class="tok-str">&quot;truecolor&quot;</span>) <span class="tok-kw">or</span></span>
<span class="line" id="L208"> std.mem.eql(<span class="tok-type">u8</span>, colorterm, <span class="tok-str">&quot;24bit&quot;</span>))</span>
<span class="line" id="L209"> {</span>
<span class="line" id="L210"> <span class="tok-kw">if</span> (<span class="tok-builtin">@hasField</span>(Event, <span class="tok-str">&quot;cap_rgb&quot;</span>)) {</span>
<span class="line" id="L211"> self.postEvent(.cap_rgb);</span>
<span class="line" id="L212"> }</span>
<span class="line" id="L213"> }</span>
<span class="line" id="L214"></span>
<span class="line" id="L215"> <span class="tok-comment">// TODO: decide if we actually want to query for focus and sync. It</span>
</span>
<span class="line" id="L216"> <span class="tok-comment">// doesn't hurt to blindly use them</span>
</span>
<span class="line" id="L217"> <span class="tok-comment">// _ = try tty.write(ctlseqs.decrqm_focus);</span>
</span>
<span class="line" id="L218"> <span class="tok-comment">// _ = try tty.write(ctlseqs.decrqm_sync);</span>
</span>
<span class="line" id="L219"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.decrqm_unicode);</span>
<span class="line" id="L220"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.decrqm_color_theme);</span>
<span class="line" id="L221"> <span class="tok-comment">// TODO: XTVERSION has a DCS response. uncomment when we can parse</span>
</span>
<span class="line" id="L222"> <span class="tok-comment">// that</span>
</span>
<span class="line" id="L223"> <span class="tok-comment">// _ = try tty.write(ctlseqs.xtversion);</span>
</span>
<span class="line" id="L224"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.csi_u_query);</span>
<span class="line" id="L225"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.kitty_graphics_query);</span>
<span class="line" id="L226"> <span class="tok-comment">// TODO: sixel geometry query interferes with F4 keys.</span>
</span>
<span class="line" id="L227"> <span class="tok-comment">// _ = try tty.write(ctlseqs.sixel_geometry_query);</span>
</span>
<span class="line" id="L228"></span>
<span class="line" id="L229"> <span class="tok-comment">// TODO: XTGETTCAP queries (&quot;RGB&quot;, &quot;Smulx&quot;)</span>
</span>
<span class="line" id="L230"></span>
<span class="line" id="L231"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.primary_device_attrs);</span>
<span class="line" id="L232"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L233"></span>
<span class="line" id="L234"> <span class="tok-comment">// 1 second timeout</span>
</span>
<span class="line" id="L235"> std.Thread.Futex.timedWait(&amp;self.query_futex, <span class="tok-number">0</span>, <span class="tok-number">1</span> * std.time.ns_per_s) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L236"></span>
<span class="line" id="L237"> <span class="tok-comment">// enable detected features</span>
</span>
<span class="line" id="L238"> <span class="tok-kw">if</span> (self.caps.kitty_keyboard) {</span>
<span class="line" id="L239"> <span class="tok-kw">try</span> self.enableKittyKeyboard(.{});</span>
<span class="line" id="L240"> }</span>
<span class="line" id="L241"> <span class="tok-kw">if</span> (self.caps.unicode) {</span>
<span class="line" id="L242"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.unicode_set);</span>
<span class="line" id="L243"> }</span>
<span class="line" id="L244"> }</span>
<span class="line" id="L245"></span>
<span class="line" id="L246"> <span class="tok-comment">// the next render call will refresh the entire screen</span>
</span>
<span class="line" id="L247"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">queueRefresh</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L248"> self.refresh = <span class="tok-null">true</span>;</span>
<span class="line" id="L249"> }</span>
<span class="line" id="L250"></span>
<span class="line" id="L251"> <span class="tok-comment">/// draws the screen to the terminal</span></span>
<span class="line" id="L252"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">render</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L253"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L254"> self.renders += <span class="tok-number">1</span>;</span>
<span class="line" id="L255"> <span class="tok-kw">const</span> timer_start = std.time.microTimestamp();</span>
<span class="line" id="L256"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L257"> self.render_dur += std.time.microTimestamp() - timer_start;</span>
<span class="line" id="L258"> }</span>
<span class="line" id="L259"></span>
<span class="line" id="L260"> <span class="tok-kw">defer</span> self.refresh = <span class="tok-null">false</span>;</span>
<span class="line" id="L261"> <span class="tok-kw">defer</span> tty.flush() <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L262"></span>
<span class="line" id="L263"> <span class="tok-comment">// Set up sync before we write anything</span>
</span>
<span class="line" id="L264"> <span class="tok-comment">// TODO: optimize sync so we only sync _when we have changes_. This</span>
</span>
<span class="line" id="L265"> <span class="tok-comment">// requires a smarter buffered writer, we'll probably have to write</span>
</span>
<span class="line" id="L266"> <span class="tok-comment">// our own</span>
</span>
<span class="line" id="L267"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.sync_set);</span>
<span class="line" id="L268"> <span class="tok-kw">defer</span> _ = tty.write(ctlseqs.sync_reset) <span class="tok-kw">catch</span> {};</span>
<span class="line" id="L269"></span>
<span class="line" id="L270"> <span class="tok-comment">// Send the cursor to 0,0</span>
</span>
<span class="line" id="L271"> <span class="tok-comment">// TODO: this needs to move after we optimize writes. We only do</span>
</span>
<span class="line" id="L272"> <span class="tok-comment">// this if we have an update to make. We also need to hide cursor</span>
</span>
<span class="line" id="L273"> <span class="tok-comment">// and then reshow it if needed</span>
</span>
<span class="line" id="L274"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.hide_cursor);</span>
<span class="line" id="L275"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.home);</span>
<span class="line" id="L276"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.sgr_reset);</span>
<span class="line" id="L277"></span>
<span class="line" id="L278"> <span class="tok-comment">// initialize some variables</span>
</span>
<span class="line" id="L279"> <span class="tok-kw">var</span> reposition: <span class="tok-type">bool</span> = <span class="tok-null">false</span>;</span>
<span class="line" id="L280"> <span class="tok-kw">var</span> row: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L281"> <span class="tok-kw">var</span> col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L282"> <span class="tok-kw">var</span> cursor: Style = .{};</span>
<span class="line" id="L283"> <span class="tok-kw">var</span> link: Hyperlink = .{};</span>
<span class="line" id="L284"></span>
<span class="line" id="L285"> <span class="tok-comment">// Clear all images</span>
</span>
<span class="line" id="L286"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.kitty_graphics_clear);</span>
<span class="line" id="L287"></span>
<span class="line" id="L288"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L289"> <span class="tok-kw">while</span> (i &lt; self.screen.buf.len) {</span>
<span class="line" id="L290"> <span class="tok-kw">const</span> cell = self.screen.buf[i];</span>
<span class="line" id="L291"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L292"> <span class="tok-comment">// advance by the width of this char mod 1</span>
</span>
<span class="line" id="L293"> <span class="tok-kw">const</span> w = blk: {</span>
<span class="line" id="L294"> <span class="tok-kw">if</span> (cell.char.width != <span class="tok-number">0</span>) <span class="tok-kw">break</span> :blk cell.char.width;</span>
<span class="line" id="L295"></span>
<span class="line" id="L296"> <span class="tok-kw">const</span> method: gwidth.Method = <span class="tok-kw">if</span> (self.caps.unicode) .unicode <span class="tok-kw">else</span> .wcwidth;</span>
<span class="line" id="L297"> <span class="tok-kw">break</span> :blk gwidth.gwidth(cell.char.grapheme, method) <span class="tok-kw">catch</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L298"> };</span>
<span class="line" id="L299"> <span class="tok-kw">var</span> j = i + <span class="tok-number">1</span>;</span>
<span class="line" id="L300"> <span class="tok-kw">while</span> (j &lt; i + w) : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L301"> self.screen_last.buf[j].skipped = <span class="tok-null">true</span>;</span>
<span class="line" id="L302"> }</span>
<span class="line" id="L303"> col += w;</span>
<span class="line" id="L304"> i += w;</span>
<span class="line" id="L305"> }</span>
<span class="line" id="L306"> <span class="tok-kw">if</span> (col &gt;= self.screen.width) {</span>
<span class="line" id="L307"> row += <span class="tok-number">1</span>;</span>
<span class="line" id="L308"> col = <span class="tok-number">0</span>;</span>
<span class="line" id="L309"> }</span>
<span class="line" id="L310"> <span class="tok-comment">// If cell is the same as our last frame, we don't need to do</span>
</span>
<span class="line" id="L311"> <span class="tok-comment">// anything</span>
</span>
<span class="line" id="L312"> <span class="tok-kw">const</span> last = self.screen_last.buf[i];</span>
<span class="line" id="L313"> <span class="tok-kw">if</span> (!self.refresh <span class="tok-kw">and</span> last.eql(cell) <span class="tok-kw">and</span> !last.skipped <span class="tok-kw">and</span> cell.image == <span class="tok-null">null</span>) {</span>
<span class="line" id="L314"> reposition = <span class="tok-null">true</span>;</span>
<span class="line" id="L315"> <span class="tok-comment">// Close any osc8 sequence we might be in before</span>
</span>
<span class="line" id="L316"> <span class="tok-comment">// repositioning</span>
</span>
<span class="line" id="L317"> <span class="tok-kw">if</span> (link.uri.len &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L318"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.osc8_clear);</span>
<span class="line" id="L319"> }</span>
<span class="line" id="L320"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L321"> }</span>
<span class="line" id="L322"> self.screen_last.buf[i].skipped = <span class="tok-null">false</span>;</span>
<span class="line" id="L323"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L324"> cursor = cell.style;</span>
<span class="line" id="L325"> link = cell.link;</span>
<span class="line" id="L326"> }</span>
<span class="line" id="L327"> <span class="tok-comment">// Set this cell in the last frame</span>
</span>
<span class="line" id="L328"> self.screen_last.writeCell(col, row, cell);</span>
<span class="line" id="L329"></span>
<span class="line" id="L330"> <span class="tok-comment">// reposition the cursor, if needed</span>
</span>
<span class="line" id="L331"> <span class="tok-kw">if</span> (reposition) {</span>
<span class="line" id="L332"> <span class="tok-kw">try</span> std.fmt.format(tty.buffered_writer.writer(), ctlseqs.cup, .{ row + <span class="tok-number">1</span>, col + <span class="tok-number">1</span> });</span>
<span class="line" id="L333"> }</span>
<span class="line" id="L334"></span>
<span class="line" id="L335"> <span class="tok-kw">if</span> (cell.image) |img| {</span>
<span class="line" id="L336"> <span class="tok-kw">if</span> (img.size) |size| {</span>
<span class="line" id="L337"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L338"> tty.buffered_writer.writer(),</span>
<span class="line" id="L339"> ctlseqs.kitty_graphics_scale,</span>
<span class="line" id="L340"> .{ img.img_id, img.z_index, size.cols, size.rows },</span>
<span class="line" id="L341"> );</span>
<span class="line" id="L342"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L343"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L344"> tty.buffered_writer.writer(),</span>
<span class="line" id="L345"> ctlseqs.kitty_graphics_place,</span>
<span class="line" id="L346"> .{ img.img_id, img.z_index },</span>
<span class="line" id="L347"> );</span>
<span class="line" id="L348"> }</span>
<span class="line" id="L349"> }</span>
<span class="line" id="L350"></span>
<span class="line" id="L351"> <span class="tok-comment">// something is different, so let's loop through everything and</span>
</span>
<span class="line" id="L352"> <span class="tok-comment">// find out what</span>
</span>
<span class="line" id="L353"></span>
<span class="line" id="L354"> <span class="tok-comment">// foreground</span>
</span>
<span class="line" id="L355"> <span class="tok-kw">if</span> (!std.meta.eql(cursor.fg, cell.style.fg)) {</span>
<span class="line" id="L356"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L357"> <span class="tok-kw">switch</span> (cell.style.fg) {</span>
<span class="line" id="L358"> .default =&gt; _ = <span class="tok-kw">try</span> tty.write(ctlseqs.fg_reset),</span>
<span class="line" id="L359"> .index =&gt; |idx| {</span>
<span class="line" id="L360"> <span class="tok-kw">switch</span> (idx) {</span>
<span class="line" id="L361"> <span class="tok-number">0</span>...<span class="tok-number">7</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.fg_base, .{idx}),</span>
<span class="line" id="L362"> <span class="tok-number">8</span>...<span class="tok-number">15</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.fg_bright, .{idx - <span class="tok-number">8</span>}),</span>
<span class="line" id="L363"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.fg_indexed, .{idx}),</span>
<span class="line" id="L364"> }</span>
<span class="line" id="L365"> },</span>
<span class="line" id="L366"> .rgb =&gt; |rgb| {</span>
<span class="line" id="L367"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.fg_rgb, .{ rgb[<span class="tok-number">0</span>], rgb[<span class="tok-number">1</span>], rgb[<span class="tok-number">2</span>] });</span>
<span class="line" id="L368"> },</span>
<span class="line" id="L369"> }</span>
<span class="line" id="L370"> }</span>
<span class="line" id="L371"> <span class="tok-comment">// background</span>
</span>
<span class="line" id="L372"> <span class="tok-kw">if</span> (!std.meta.eql(cursor.bg, cell.style.bg)) {</span>
<span class="line" id="L373"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L374"> <span class="tok-kw">switch</span> (cell.style.bg) {</span>
<span class="line" id="L375"> .default =&gt; _ = <span class="tok-kw">try</span> tty.write(ctlseqs.bg_reset),</span>
<span class="line" id="L376"> .index =&gt; |idx| {</span>
<span class="line" id="L377"> <span class="tok-kw">switch</span> (idx) {</span>
<span class="line" id="L378"> <span class="tok-number">0</span>...<span class="tok-number">7</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.bg_base, .{idx}),</span>
<span class="line" id="L379"> <span class="tok-number">8</span>...<span class="tok-number">15</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.bg_bright, .{idx - <span class="tok-number">8</span>}),</span>
<span class="line" id="L380"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.bg_indexed, .{idx}),</span>
<span class="line" id="L381"> }</span>
<span class="line" id="L382"> },</span>
<span class="line" id="L383"> .rgb =&gt; |rgb| {</span>
<span class="line" id="L384"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.bg_rgb, .{ rgb[<span class="tok-number">0</span>], rgb[<span class="tok-number">1</span>], rgb[<span class="tok-number">2</span>] });</span>
<span class="line" id="L385"> },</span>
<span class="line" id="L386"> }</span>
<span class="line" id="L387"> }</span>
<span class="line" id="L388"> <span class="tok-comment">// underline color</span>
</span>
<span class="line" id="L389"> <span class="tok-kw">if</span> (!std.meta.eql(cursor.ul, cell.style.ul)) {</span>
<span class="line" id="L390"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L391"> <span class="tok-kw">switch</span> (cell.style.bg) {</span>
<span class="line" id="L392"> .default =&gt; _ = <span class="tok-kw">try</span> tty.write(ctlseqs.ul_reset),</span>
<span class="line" id="L393"> .index =&gt; |idx| {</span>
<span class="line" id="L394"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.ul_indexed, .{idx});</span>
<span class="line" id="L395"> },</span>
<span class="line" id="L396"> .rgb =&gt; |rgb| {</span>
<span class="line" id="L397"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.ul_rgb, .{ rgb[<span class="tok-number">0</span>], rgb[<span class="tok-number">1</span>], rgb[<span class="tok-number">2</span>] });</span>
<span class="line" id="L398"> },</span>
<span class="line" id="L399"> }</span>
<span class="line" id="L400"> }</span>
<span class="line" id="L401"> <span class="tok-comment">// underline style</span>
</span>
<span class="line" id="L402"> <span class="tok-kw">if</span> (!std.meta.eql(cursor.ul_style, cell.style.ul_style)) {</span>
<span class="line" id="L403"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.ul_style) {</span>
<span class="line" id="L404"> .off =&gt; ctlseqs.ul_off,</span>
<span class="line" id="L405"> .single =&gt; ctlseqs.ul_single,</span>
<span class="line" id="L406"> .double =&gt; ctlseqs.ul_double,</span>
<span class="line" id="L407"> .curly =&gt; ctlseqs.ul_curly,</span>
<span class="line" id="L408"> .dotted =&gt; ctlseqs.ul_dotted,</span>
<span class="line" id="L409"> .dashed =&gt; ctlseqs.ul_dashed,</span>
<span class="line" id="L410"> };</span>
<span class="line" id="L411"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L412"> }</span>
<span class="line" id="L413"> <span class="tok-comment">// bold</span>
</span>
<span class="line" id="L414"> <span class="tok-kw">if</span> (cursor.bold != cell.style.bold) {</span>
<span class="line" id="L415"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.bold) {</span>
<span class="line" id="L416"> <span class="tok-null">true</span> =&gt; ctlseqs.bold_set,</span>
<span class="line" id="L417"> <span class="tok-null">false</span> =&gt; ctlseqs.bold_dim_reset,</span>
<span class="line" id="L418"> };</span>
<span class="line" id="L419"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L420"> <span class="tok-kw">if</span> (cell.style.dim) {</span>
<span class="line" id="L421"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.dim_set);</span>
<span class="line" id="L422"> }</span>
<span class="line" id="L423"> }</span>
<span class="line" id="L424"> <span class="tok-comment">// dim</span>
</span>
<span class="line" id="L425"> <span class="tok-kw">if</span> (cursor.dim != cell.style.dim) {</span>
<span class="line" id="L426"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.dim) {</span>
<span class="line" id="L427"> <span class="tok-null">true</span> =&gt; ctlseqs.dim_set,</span>
<span class="line" id="L428"> <span class="tok-null">false</span> =&gt; ctlseqs.bold_dim_reset,</span>
<span class="line" id="L429"> };</span>
<span class="line" id="L430"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L431"> <span class="tok-kw">if</span> (cell.style.bold) {</span>
<span class="line" id="L432"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.bold_set);</span>
<span class="line" id="L433"> }</span>
<span class="line" id="L434"> }</span>
<span class="line" id="L435"> <span class="tok-comment">// dim</span>
</span>
<span class="line" id="L436"> <span class="tok-kw">if</span> (cursor.italic != cell.style.italic) {</span>
<span class="line" id="L437"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.italic) {</span>
<span class="line" id="L438"> <span class="tok-null">true</span> =&gt; ctlseqs.italic_set,</span>
<span class="line" id="L439"> <span class="tok-null">false</span> =&gt; ctlseqs.italic_reset,</span>
<span class="line" id="L440"> };</span>
<span class="line" id="L441"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L442"> }</span>
<span class="line" id="L443"> <span class="tok-comment">// dim</span>
</span>
<span class="line" id="L444"> <span class="tok-kw">if</span> (cursor.blink != cell.style.blink) {</span>
<span class="line" id="L445"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.blink) {</span>
<span class="line" id="L446"> <span class="tok-null">true</span> =&gt; ctlseqs.blink_set,</span>
<span class="line" id="L447"> <span class="tok-null">false</span> =&gt; ctlseqs.blink_reset,</span>
<span class="line" id="L448"> };</span>
<span class="line" id="L449"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L450"> }</span>
<span class="line" id="L451"> <span class="tok-comment">// reverse</span>
</span>
<span class="line" id="L452"> <span class="tok-kw">if</span> (cursor.reverse != cell.style.reverse) {</span>
<span class="line" id="L453"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.reverse) {</span>
<span class="line" id="L454"> <span class="tok-null">true</span> =&gt; ctlseqs.reverse_set,</span>
<span class="line" id="L455"> <span class="tok-null">false</span> =&gt; ctlseqs.reverse_reset,</span>
<span class="line" id="L456"> };</span>
<span class="line" id="L457"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L458"> }</span>
<span class="line" id="L459"> <span class="tok-comment">// invisible</span>
</span>
<span class="line" id="L460"> <span class="tok-kw">if</span> (cursor.invisible != cell.style.invisible) {</span>
<span class="line" id="L461"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.invisible) {</span>
<span class="line" id="L462"> <span class="tok-null">true</span> =&gt; ctlseqs.invisible_set,</span>
<span class="line" id="L463"> <span class="tok-null">false</span> =&gt; ctlseqs.invisible_reset,</span>
<span class="line" id="L464"> };</span>
<span class="line" id="L465"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L466"> }</span>
<span class="line" id="L467"> <span class="tok-comment">// strikethrough</span>
</span>
<span class="line" id="L468"> <span class="tok-kw">if</span> (cursor.strikethrough != cell.style.strikethrough) {</span>
<span class="line" id="L469"> <span class="tok-kw">const</span> seq = <span class="tok-kw">switch</span> (cell.style.strikethrough) {</span>
<span class="line" id="L470"> <span class="tok-null">true</span> =&gt; ctlseqs.strikethrough_set,</span>
<span class="line" id="L471"> <span class="tok-null">false</span> =&gt; ctlseqs.strikethrough_reset,</span>
<span class="line" id="L472"> };</span>
<span class="line" id="L473"> _ = <span class="tok-kw">try</span> tty.write(seq);</span>
<span class="line" id="L474"> }</span>
<span class="line" id="L475"></span>
<span class="line" id="L476"> <span class="tok-comment">// url</span>
</span>
<span class="line" id="L477"> <span class="tok-kw">if</span> (!std.meta.eql(link.uri, cell.link.uri)) {</span>
<span class="line" id="L478"> <span class="tok-kw">var</span> ps = cell.link.params;</span>
<span class="line" id="L479"> <span class="tok-kw">if</span> (cell.link.uri.len == <span class="tok-number">0</span>) {</span>
<span class="line" id="L480"> <span class="tok-comment">// Empty out the params no matter what if we don't have</span>
</span>
<span class="line" id="L481"> <span class="tok-comment">// a url</span>
</span>
<span class="line" id="L482"> ps = <span class="tok-str">&quot;&quot;</span>;</span>
<span class="line" id="L483"> }</span>
<span class="line" id="L484"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L485"> <span class="tok-kw">try</span> std.fmt.format(writer, ctlseqs.osc8, .{ ps, cell.link.uri });</span>
<span class="line" id="L486"> }</span>
<span class="line" id="L487"> _ = <span class="tok-kw">try</span> tty.write(cell.char.grapheme);</span>
<span class="line" id="L488"> }</span>
<span class="line" id="L489"> <span class="tok-kw">if</span> (self.screen.cursor_vis) {</span>
<span class="line" id="L490"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L491"> tty.buffered_writer.writer(),</span>
<span class="line" id="L492"> ctlseqs.cup,</span>
<span class="line" id="L493"> .{</span>
<span class="line" id="L494"> self.screen.cursor_row + <span class="tok-number">1</span>,</span>
<span class="line" id="L495"> self.screen.cursor_col + <span class="tok-number">1</span>,</span>
<span class="line" id="L496"> },</span>
<span class="line" id="L497"> );</span>
<span class="line" id="L498"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.show_cursor);</span>
<span class="line" id="L499"> }</span>
<span class="line" id="L500"> <span class="tok-kw">if</span> (self.screen.mouse_shape != self.screen_last.mouse_shape) {</span>
<span class="line" id="L501"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L502"> tty.buffered_writer.writer(),</span>
<span class="line" id="L503"> ctlseqs.osc22_mouse_shape,</span>
<span class="line" id="L504"> .{<span class="tok-builtin">@tagName</span>(self.screen.mouse_shape)},</span>
<span class="line" id="L505"> );</span>
<span class="line" id="L506"> }</span>
<span class="line" id="L507"> }</span>
<span class="line" id="L508"></span>
<span class="line" id="L509"> <span class="tok-kw">fn</span> <span class="tok-fn">enableKittyKeyboard</span>(self: *Self, flags: Key.KittyFlags) !<span class="tok-type">void</span> {</span>
<span class="line" id="L510"> self.state.kitty_keyboard = <span class="tok-null">true</span>;</span>
<span class="line" id="L511"> <span class="tok-kw">const</span> flag_int: <span class="tok-type">u5</span> = <span class="tok-builtin">@bitCast</span>(flags);</span>
<span class="line" id="L512"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L513"> self.tty.?.buffered_writer.writer(),</span>
<span class="line" id="L514"> ctlseqs.csi_u_push,</span>
<span class="line" id="L515"> .{</span>
<span class="line" id="L516"> flag_int,</span>
<span class="line" id="L517"> },</span>
<span class="line" id="L518"> );</span>
<span class="line" id="L519"> <span class="tok-kw">try</span> self.tty.?.flush();</span>
<span class="line" id="L520"> }</span>
<span class="line" id="L521"></span>
<span class="line" id="L522"> <span class="tok-comment">/// send a system notification</span></span>
<span class="line" id="L523"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">notify</span>(self: *Self, title: ?[]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, body: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L524"> <span class="tok-kw">if</span> (self.tty == <span class="tok-null">null</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L525"> <span class="tok-kw">if</span> (title) |t| {</span>
<span class="line" id="L526"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L527"> self.tty.?.buffered_writer.writer(),</span>
<span class="line" id="L528"> ctlseqs.osc777_notify,</span>
<span class="line" id="L529"> .{ t, body },</span>
<span class="line" id="L530"> );</span>
<span class="line" id="L531"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L532"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L533"> self.tty.?.buffered_writer.writer(),</span>
<span class="line" id="L534"> ctlseqs.osc9_notify,</span>
<span class="line" id="L535"> .{body},</span>
<span class="line" id="L536"> );</span>
<span class="line" id="L537"> }</span>
<span class="line" id="L538"> <span class="tok-kw">try</span> self.tty.?.flush();</span>
<span class="line" id="L539"> }</span>
<span class="line" id="L540"></span>
<span class="line" id="L541"> <span class="tok-comment">/// sets the window title</span></span>
<span class="line" id="L542"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setTitle</span>(self: *Self, title: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L543"> <span class="tok-kw">if</span> (self.tty == <span class="tok-null">null</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L544"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L545"> self.tty.?.buffered_writer.writer(),</span>
<span class="line" id="L546"> ctlseqs.osc2_set_title,</span>
<span class="line" id="L547"> .{title},</span>
<span class="line" id="L548"> );</span>
<span class="line" id="L549"> <span class="tok-kw">try</span> self.tty.?.flush();</span>
<span class="line" id="L550"> }</span>
<span class="line" id="L551"></span>
<span class="line" id="L552"> <span class="tok-comment">// turn bracketed paste on or off. An event will be sent at the</span>
</span>
<span class="line" id="L553"> <span class="tok-comment">// beginning and end of a detected paste. All keystrokes between these</span>
</span>
<span class="line" id="L554"> <span class="tok-comment">// events were pasted</span>
</span>
<span class="line" id="L555"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setBracketedPaste</span>(self: *Self, enable: <span class="tok-type">bool</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L556"> <span class="tok-kw">if</span> (self.tty == <span class="tok-null">null</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L557"> self.state.bracketed_paste = enable;</span>
<span class="line" id="L558"> <span class="tok-kw">const</span> seq = <span class="tok-kw">if</span> (enable) {</span>
<span class="line" id="L559"> self.state.bracketed_paste = <span class="tok-null">true</span>;</span>
<span class="line" id="L560"> ctlseqs.bp_set;</span>
<span class="line" id="L561"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L562"> self.state.bracketed_paste = <span class="tok-null">true</span>;</span>
<span class="line" id="L563"> ctlseqs.bp_reset;</span>
<span class="line" id="L564"> };</span>
<span class="line" id="L565"> _ = <span class="tok-kw">try</span> self.tty.?.write(seq);</span>
<span class="line" id="L566"> <span class="tok-kw">try</span> self.tty.?.flush();</span>
<span class="line" id="L567"> }</span>
<span class="line" id="L568"></span>
<span class="line" id="L569"> <span class="tok-comment">/// set the mouse shape</span></span>
<span class="line" id="L570"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setMouseShape</span>(self: *Self, shape: Shape) <span class="tok-type">void</span> {</span>
<span class="line" id="L571"> self.screen.mouse_shape = shape;</span>
<span class="line" id="L572"> }</span>
<span class="line" id="L573"></span>
<span class="line" id="L574"> <span class="tok-comment">/// turn mouse reporting on or off</span></span>
<span class="line" id="L575"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setMouseMode</span>(self: *Self, enable: <span class="tok-type">bool</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L576"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L577"> self.state.mouse = enable;</span>
<span class="line" id="L578"> <span class="tok-kw">if</span> (enable) {</span>
<span class="line" id="L579"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.mouse_set);</span>
<span class="line" id="L580"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L581"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L582"> _ = <span class="tok-kw">try</span> tty.write(ctlseqs.mouse_reset);</span>
<span class="line" id="L583"> <span class="tok-kw">try</span> tty.flush();</span>
<span class="line" id="L584"> }</span>
<span class="line" id="L585"> }</span>
<span class="line" id="L586"></span>
<span class="line" id="L587"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">loadImage</span>(</span>
<span class="line" id="L588"> self: *Self,</span>
<span class="line" id="L589"> alloc: std.mem.Allocator,</span>
<span class="line" id="L590"> src: Image.Source,</span>
<span class="line" id="L591"> ) !Image {</span>
<span class="line" id="L592"> <span class="tok-kw">if</span> (!self.caps.kitty_graphics) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.NoGraphicsCapability;</span>
<span class="line" id="L593"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.NoTTY;</span>
<span class="line" id="L594"> <span class="tok-kw">defer</span> self.next_img_id += <span class="tok-number">1</span>;</span>
<span class="line" id="L595"></span>
<span class="line" id="L596"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L597"></span>
<span class="line" id="L598"> <span class="tok-kw">var</span> img = <span class="tok-kw">switch</span> (src) {</span>
<span class="line" id="L599"> .path =&gt; |path| <span class="tok-kw">try</span> zigimg.Image.fromFilePath(alloc, path),</span>
<span class="line" id="L600"> .mem =&gt; |bytes| <span class="tok-kw">try</span> zigimg.Image.fromMemory(alloc, bytes),</span>
<span class="line" id="L601"> };</span>
<span class="line" id="L602"> <span class="tok-kw">defer</span> img.deinit();</span>
<span class="line" id="L603"> <span class="tok-kw">const</span> png_buf = <span class="tok-kw">try</span> alloc.alloc(<span class="tok-type">u8</span>, img.imageByteSize());</span>
<span class="line" id="L604"> <span class="tok-kw">defer</span> alloc.free(png_buf);</span>
<span class="line" id="L605"> <span class="tok-kw">const</span> png = <span class="tok-kw">try</span> img.writeToMemory(png_buf, .{ .png = .{} });</span>
<span class="line" id="L606"> <span class="tok-kw">const</span> b64_buf = <span class="tok-kw">try</span> alloc.alloc(<span class="tok-type">u8</span>, base64.calcSize(png.len));</span>
<span class="line" id="L607"> <span class="tok-kw">const</span> encoded = base64.encode(b64_buf, png);</span>
<span class="line" id="L608"> <span class="tok-kw">defer</span> alloc.free(b64_buf);</span>
<span class="line" id="L609"></span>
<span class="line" id="L610"> <span class="tok-kw">const</span> id = self.next_img_id;</span>
<span class="line" id="L611"></span>
<span class="line" id="L612"> log.debug(<span class="tok-str">&quot;transmitting kitty image: id={d}, len={d}&quot;</span>, .{ id, encoded.len });</span>
<span class="line" id="L613"></span>
<span class="line" id="L614"> <span class="tok-kw">if</span> (encoded.len &lt; <span class="tok-number">4096</span>) {</span>
<span class="line" id="L615"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L616"> writer,</span>
<span class="line" id="L617"> <span class="tok-str">&quot;\x1b_Gf=100,i={d};{s}\x1b\\&quot;</span>,</span>
<span class="line" id="L618"> .{</span>
<span class="line" id="L619"> id,</span>
<span class="line" id="L620"> encoded,</span>
<span class="line" id="L621"> },</span>
<span class="line" id="L622"> );</span>
<span class="line" id="L623"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L624"> <span class="tok-kw">var</span> n: <span class="tok-type">usize</span> = <span class="tok-number">4096</span>;</span>
<span class="line" id="L625"></span>
<span class="line" id="L626"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L627"> writer,</span>
<span class="line" id="L628"> <span class="tok-str">&quot;\x1b_Gf=100,i={d},m=1;{s}\x1b\\&quot;</span>,</span>
<span class="line" id="L629"> .{ id, encoded[<span class="tok-number">0</span>..n] },</span>
<span class="line" id="L630"> );</span>
<span class="line" id="L631"> <span class="tok-kw">while</span> (n &lt; encoded.len) : (n += <span class="tok-number">4096</span>) {</span>
<span class="line" id="L632"> <span class="tok-kw">const</span> end: <span class="tok-type">usize</span> = <span class="tok-builtin">@min</span>(n + <span class="tok-number">4096</span>, encoded.len);</span>
<span class="line" id="L633"> <span class="tok-kw">const</span> m: <span class="tok-type">u2</span> = <span class="tok-kw">if</span> (end == encoded.len) <span class="tok-number">0</span> <span class="tok-kw">else</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L634"> <span class="tok-kw">try</span> std.fmt.format(</span>
<span class="line" id="L635"> writer,</span>
<span class="line" id="L636"> <span class="tok-str">&quot;\x1b_Gm={d};{s}\x1b\\&quot;</span>,</span>
<span class="line" id="L637"> .{</span>
<span class="line" id="L638"> m,</span>
<span class="line" id="L639"> encoded[n..end],</span>
<span class="line" id="L640"> },</span>
<span class="line" id="L641"> );</span>
<span class="line" id="L642"> }</span>
<span class="line" id="L643"> }</span>
<span class="line" id="L644"> <span class="tok-kw">try</span> tty.buffered_writer.flush();</span>
<span class="line" id="L645"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L646"> .id = id,</span>
<span class="line" id="L647"> .width = img.width,</span>
<span class="line" id="L648"> .height = img.height,</span>
<span class="line" id="L649"> };</span>
<span class="line" id="L650"> }</span>
<span class="line" id="L651"></span>
<span class="line" id="L652"> <span class="tok-comment">/// deletes an image from the terminal's memory</span></span>
<span class="line" id="L653"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">freeImage</span>(self: Self, id: <span class="tok-type">u32</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L654"> <span class="tok-kw">var</span> tty = self.tty <span class="tok-kw">orelse</span> <span class="tok-kw">return</span>;</span>
<span class="line" id="L655"> <span class="tok-kw">const</span> writer = tty.buffered_writer.writer();</span>
<span class="line" id="L656"> std.fmt.format(writer, <span class="tok-str">&quot;\x1b_Ga=d,d=I,i={d};\x1b\\&quot;</span>, .{id}) <span class="tok-kw">catch</span> |err| {</span>
<span class="line" id="L657"> log.err(<span class="tok-str">&quot;couldn't delete image {d}: {}&quot;</span>, .{ id, err });</span>
<span class="line" id="L658"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L659"> };</span>
<span class="line" id="L660"> tty.buffered_writer.flush() <span class="tok-kw">catch</span> |err| {</span>
<span class="line" id="L661"> log.err(<span class="tok-str">&quot;couldn't flush writer: {}&quot;</span>, .{err});</span>
<span class="line" id="L662"> };</span>
<span class="line" id="L663"> }</span>
<span class="line" id="L664"> };</span>
<span class="line" id="L665">}</span>
<span class="line" id="L666"></span>
<span class="line" id="L667"><span class="tok-kw">test</span> <span class="tok-str">&quot;Vaxis: event queueing&quot;</span> {</span>
<span class="line" id="L668"> <span class="tok-kw">const</span> Event = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L669"> key,</span>
<span class="line" id="L670"> };</span>
<span class="line" id="L671"> <span class="tok-kw">var</span> vx: Vaxis(Event) = <span class="tok-kw">try</span> Vaxis(Event).init(.{});</span>
<span class="line" id="L672"> <span class="tok-kw">defer</span> vx.deinit(<span class="tok-null">null</span>);</span>
<span class="line" id="L673"> vx.postEvent(.key);</span>
<span class="line" id="L674"> <span class="tok-kw">const</span> event = vx.nextEvent();</span>
<span class="line" id="L675"> <span class="tok-kw">try</span> std.testing.expect(event == .key);</span>
<span class="line" id="L676">}</span>
<span class="line" id="L677"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,120 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> border = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets/border.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> alignment = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets/alignment.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> TextInput = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;widgets/TextInput.zig&quot;</span>);</span>
<span class="line" id="L4"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,260 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets/TextInput.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> Key = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Key.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Cell.zig&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Window.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> GraphemeIterator = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph&quot;</span>).GraphemeIterator;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> log = std.log.scoped(.text_input);</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> TextInput = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-comment">/// The events that this widget handles</span></span>
<span class="line" id="L12"><span class="tok-kw">const</span> Event = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L13"> key_press: Key,</span>
<span class="line" id="L14">};</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-comment">// Index of our cursor</span>
</span>
<span class="line" id="L17">cursor_idx: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L18">grapheme_count: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-comment">// TODO: an ArrayList is not great for this. orderedRemove is O(n) and we can</span>
</span>
<span class="line" id="L21"><span class="tok-comment">// only remove one byte at a time. Make a bespoke ArrayList which allows removal</span>
</span>
<span class="line" id="L22"><span class="tok-comment">// of a slice at a time, or truncating even would be nice</span>
</span>
<span class="line" id="L23">buf: std.ArrayList(<span class="tok-type">u8</span>),</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(alloc: std.mem.Allocator) TextInput {</span>
<span class="line" id="L26"> <span class="tok-kw">return</span> TextInput{</span>
<span class="line" id="L27"> .buf = std.ArrayList(<span class="tok-type">u8</span>).init(alloc),</span>
<span class="line" id="L28"> };</span>
<span class="line" id="L29">}</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *TextInput) <span class="tok-type">void</span> {</span>
<span class="line" id="L32"> self.buf.deinit();</span>
<span class="line" id="L33">}</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">update</span>(self: *TextInput, event: Event) !<span class="tok-type">void</span> {</span>
<span class="line" id="L36"> <span class="tok-kw">switch</span> (event) {</span>
<span class="line" id="L37"> .key_press =&gt; |key| {</span>
<span class="line" id="L38"> <span class="tok-kw">if</span> (key.matches(Key.backspace, .{})) {</span>
<span class="line" id="L39"> <span class="tok-kw">if</span> (self.cursor_idx == <span class="tok-number">0</span>) <span class="tok-kw">return</span>;</span>
<span class="line" id="L40"> self.deleteBeforeCursor();</span>
<span class="line" id="L41"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(Key.delete, .{}) <span class="tok-kw">or</span> key.matches(<span class="tok-str">'d'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L42"> <span class="tok-kw">if</span> (self.cursor_idx == self.grapheme_count) <span class="tok-kw">return</span>;</span>
<span class="line" id="L43"> self.deleteAtCursor();</span>
<span class="line" id="L44"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(Key.left, .{}) <span class="tok-kw">or</span> key.matches(<span class="tok-str">'b'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L45"> <span class="tok-kw">if</span> (self.cursor_idx &gt; <span class="tok-number">0</span>) self.cursor_idx -= <span class="tok-number">1</span>;</span>
<span class="line" id="L46"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(Key.right, .{}) <span class="tok-kw">or</span> key.matches(<span class="tok-str">'f'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L47"> <span class="tok-kw">if</span> (self.cursor_idx &lt; self.grapheme_count) self.cursor_idx += <span class="tok-number">1</span>;</span>
<span class="line" id="L48"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(<span class="tok-str">'a'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L49"> self.cursor_idx = <span class="tok-number">0</span>;</span>
<span class="line" id="L50"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(<span class="tok-str">'e'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L51"> self.cursor_idx = self.grapheme_count;</span>
<span class="line" id="L52"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(<span class="tok-str">'k'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L53"> <span class="tok-kw">while</span> (self.cursor_idx &lt; self.grapheme_count) {</span>
<span class="line" id="L54"> self.deleteAtCursor();</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.matches(<span class="tok-str">'u'</span>, .{ .ctrl = <span class="tok-null">true</span> })) {</span>
<span class="line" id="L57"> <span class="tok-kw">while</span> (self.cursor_idx &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L58"> self.deleteBeforeCursor();</span>
<span class="line" id="L59"> }</span>
<span class="line" id="L60"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (key.text) |text| {</span>
<span class="line" id="L61"> <span class="tok-kw">try</span> self.buf.insertSlice(self.byteOffsetToCursor(), text);</span>
<span class="line" id="L62"> self.cursor_idx += <span class="tok-number">1</span>;</span>
<span class="line" id="L63"> self.grapheme_count += <span class="tok-number">1</span>;</span>
<span class="line" id="L64"> }</span>
<span class="line" id="L65"> },</span>
<span class="line" id="L66"> }</span>
<span class="line" id="L67">}</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">draw</span>(self: *TextInput, win: Window) <span class="tok-type">void</span> {</span>
<span class="line" id="L70"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(self.buf.items);</span>
<span class="line" id="L71"> <span class="tok-kw">var</span> col: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L72"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L73"> <span class="tok-kw">var</span> cursor_idx: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L74"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L75"> <span class="tok-kw">const</span> g = grapheme.slice(self.buf.items);</span>
<span class="line" id="L76"> <span class="tok-kw">const</span> w = win.gwidth(g);</span>
<span class="line" id="L77"> win.writeCell(col, <span class="tok-number">0</span>, .{</span>
<span class="line" id="L78"> .char = .{</span>
<span class="line" id="L79"> .grapheme = g,</span>
<span class="line" id="L80"> .width = w,</span>
<span class="line" id="L81"> },</span>
<span class="line" id="L82"> });</span>
<span class="line" id="L83"> col += w;</span>
<span class="line" id="L84"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L85"> <span class="tok-kw">if</span> (i == self.cursor_idx) cursor_idx = col;</span>
<span class="line" id="L86"> }</span>
<span class="line" id="L87"> win.showCursor(cursor_idx, <span class="tok-number">0</span>);</span>
<span class="line" id="L88">}</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"><span class="tok-comment">// returns the number of bytes before the cursor</span>
</span>
<span class="line" id="L91"><span class="tok-kw">fn</span> <span class="tok-fn">byteOffsetToCursor</span>(self: TextInput) <span class="tok-type">usize</span> {</span>
<span class="line" id="L92"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(self.buf.items);</span>
<span class="line" id="L93"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L94"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L95"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L96"> <span class="tok-kw">if</span> (i == self.cursor_idx) <span class="tok-kw">break</span>;</span>
<span class="line" id="L97"> offset += grapheme.len;</span>
<span class="line" id="L98"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L99"> }</span>
<span class="line" id="L100"> <span class="tok-kw">return</span> offset;</span>
<span class="line" id="L101">}</span>
<span class="line" id="L102"></span>
<span class="line" id="L103"><span class="tok-kw">fn</span> <span class="tok-fn">deleteBeforeCursor</span>(self: *TextInput) <span class="tok-type">void</span> {</span>
<span class="line" id="L104"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(self.buf.items);</span>
<span class="line" id="L105"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L106"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L107"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L108"> <span class="tok-kw">if</span> (i == self.cursor_idx) {</span>
<span class="line" id="L109"> <span class="tok-kw">var</span> j: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L110"> <span class="tok-kw">while</span> (j &lt; grapheme.len) : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L111"> _ = self.buf.orderedRemove(offset);</span>
<span class="line" id="L112"> }</span>
<span class="line" id="L113"> self.cursor_idx -= <span class="tok-number">1</span>;</span>
<span class="line" id="L114"> self.grapheme_count -= <span class="tok-number">1</span>;</span>
<span class="line" id="L115"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"> offset += grapheme.len;</span>
<span class="line" id="L118"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L119"> }</span>
<span class="line" id="L120">}</span>
<span class="line" id="L121"></span>
<span class="line" id="L122"><span class="tok-kw">fn</span> <span class="tok-fn">deleteAtCursor</span>(self: *TextInput) <span class="tok-type">void</span> {</span>
<span class="line" id="L123"> <span class="tok-kw">var</span> iter = GraphemeIterator.init(self.buf.items);</span>
<span class="line" id="L124"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L125"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L126"> <span class="tok-kw">while</span> (iter.next()) |grapheme| {</span>
<span class="line" id="L127"> <span class="tok-kw">if</span> (i == self.cursor_idx + <span class="tok-number">1</span>) {</span>
<span class="line" id="L128"> <span class="tok-kw">var</span> j: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L129"> <span class="tok-kw">while</span> (j &lt; grapheme.len) : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L130"> _ = self.buf.orderedRemove(offset);</span>
<span class="line" id="L131"> }</span>
<span class="line" id="L132"> self.grapheme_count -= <span class="tok-number">1</span>;</span>
<span class="line" id="L133"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L134"> }</span>
<span class="line" id="L135"> offset += grapheme.len;</span>
<span class="line" id="L136"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L137"> }</span>
<span class="line" id="L138">}</span>
<span class="line" id="L139"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,124 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets/alignment.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Window.zig&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">center</span>(parent: Window, cols: <span class="tok-type">usize</span>, rows: <span class="tok-type">usize</span>) Window {</span>
<span class="line" id="L4"> <span class="tok-kw">const</span> y_off = (parent.height / <span class="tok-number">2</span>) - (rows / <span class="tok-number">2</span>);</span>
<span class="line" id="L5"> <span class="tok-kw">const</span> x_off = (parent.width / <span class="tok-number">2</span>) - (cols / <span class="tok-number">2</span>);</span>
<span class="line" id="L6"> <span class="tok-kw">return</span> parent.initChild(x_off, y_off, .{ .limit = cols }, .{ .limit = rows });</span>
<span class="line" id="L7">}</span>
<span class="line" id="L8"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,149 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>widgets/border.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> Cell = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Cell.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> Window = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Window.zig&quot;</span>);</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> Style = Cell.Style;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Character = Cell.Character;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> horizontal = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L8"><span class="tok-kw">const</span> vertical = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L9"><span class="tok-kw">const</span> top_left = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L10"><span class="tok-kw">const</span> top_right = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L11"><span class="tok-kw">const</span> bottom_right = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L12"><span class="tok-kw">const</span> bottom_left = Character{ .grapheme = <span class="tok-str">&quot;&quot;</span>, .width = <span class="tok-number">1</span> };</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">all</span>(win: Window, style: Style) Window {</span>
<span class="line" id="L15"> <span class="tok-kw">const</span> h = win.height;</span>
<span class="line" id="L16"> <span class="tok-kw">const</span> w = win.width;</span>
<span class="line" id="L17"> win.writeCell(<span class="tok-number">0</span>, <span class="tok-number">0</span>, .{ .char = top_left, .style = style });</span>
<span class="line" id="L18"> win.writeCell(<span class="tok-number">0</span>, h - <span class="tok-number">1</span>, .{ .char = bottom_left, .style = style });</span>
<span class="line" id="L19"> win.writeCell(w - <span class="tok-number">1</span>, <span class="tok-number">0</span>, .{ .char = top_right, .style = style });</span>
<span class="line" id="L20"> win.writeCell(w - <span class="tok-number">1</span>, h - <span class="tok-number">1</span>, .{ .char = bottom_right, .style = style });</span>
<span class="line" id="L21"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L22"> <span class="tok-kw">while</span> (i &lt; (h - <span class="tok-number">1</span>)) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L23"> win.writeCell(<span class="tok-number">0</span>, i, .{ .char = vertical, .style = style });</span>
<span class="line" id="L24"> win.writeCell(w - <span class="tok-number">1</span>, i, .{ .char = vertical, .style = style });</span>
<span class="line" id="L25"> }</span>
<span class="line" id="L26"> i = <span class="tok-number">1</span>;</span>
<span class="line" id="L27"> <span class="tok-kw">while</span> (i &lt; w - <span class="tok-number">1</span>) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L28"> win.writeCell(i, <span class="tok-number">0</span>, .{ .char = horizontal, .style = style });</span>
<span class="line" id="L29"> win.writeCell(i, h - <span class="tok-number">1</span>, .{ .char = horizontal, .style = style });</span>
<span class="line" id="L30"> }</span>
<span class="line" id="L31"> <span class="tok-kw">return</span> win.initChild(<span class="tok-number">1</span>, <span class="tok-number">1</span>, .{ .limit = w - <span class="tok-number">2</span> }, .{ .limit = w - <span class="tok-number">2</span> });</span>
<span class="line" id="L32">}</span>
<span class="line" id="L33"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,132 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/FormatInterface.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Image.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;color.zig&quot;</span>);</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-comment">// mlarouche: Because this is a interface, I use Zig function naming convention instead of the variable naming convention</span>
</span>
<span class="line" id="L6">format: *<span class="tok-kw">const</span> FormatFn,</span>
<span class="line" id="L7">formatDetect: *<span class="tok-kw">const</span> FormatDetectFn,</span>
<span class="line" id="L8">readImage: *<span class="tok-kw">const</span> ReadImageFn,</span>
<span class="line" id="L9">writeImage: *<span class="tok-kw">const</span> WriteImageFn,</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FormatFn = <span class="tok-kw">fn</span> () Image.Format;</span>
<span class="line" id="L12"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FormatDetectFn = <span class="tok-kw">fn</span> (stream: *Image.Stream) Image.ReadError!<span class="tok-type">bool</span>;</span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ReadImageFn = <span class="tok-kw">fn</span> (allocator: std.mem.Allocator, stream: *Image.Stream) Image.ReadError!Image;</span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> WriteImageFn = <span class="tok-kw">fn</span> (allocator: std.mem.Allocator, write_stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) Image.WriteError!<span class="tok-type">void</span>;</span>
<span class="line" id="L15"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,370 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/Image.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> AllImageFormats = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;formats/all.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;color.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> utils = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Error = <span class="tok-kw">error</span>{</span>
<span class="line" id="L9"> Unsupported,</span>
<span class="line" id="L10">};</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ReadError = Error ||</span>
<span class="line" id="L13"> std.mem.Allocator.Error ||</span>
<span class="line" id="L14"> utils.StructReadError ||</span>
<span class="line" id="L15"> std.io.StreamSource.SeekError ||</span>
<span class="line" id="L16"> std.io.StreamSource.GetSeekPosError ||</span>
<span class="line" id="L17"> <span class="tok-kw">error</span>{ EndOfStream, StreamTooLong, InvalidData };</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> WriteError = Error ||</span>
<span class="line" id="L20"> std.mem.Allocator.Error ||</span>
<span class="line" id="L21"> std.io.StreamSource.WriteError ||</span>
<span class="line" id="L22"> std.io.StreamSource.SeekError ||</span>
<span class="line" id="L23"> std.io.StreamSource.GetSeekPosError ||</span>
<span class="line" id="L24"> std.fs.File.OpenError ||</span>
<span class="line" id="L25"> <span class="tok-kw">error</span>{ EndOfStream, InvalidData };</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Format = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L28"> bmp,</span>
<span class="line" id="L29"> gif,</span>
<span class="line" id="L30"> jpg,</span>
<span class="line" id="L31"> pbm,</span>
<span class="line" id="L32"> pcx,</span>
<span class="line" id="L33"> pgm,</span>
<span class="line" id="L34"> png,</span>
<span class="line" id="L35"> ppm,</span>
<span class="line" id="L36"> qoi,</span>
<span class="line" id="L37"> tga,</span>
<span class="line" id="L38"> pam,</span>
<span class="line" id="L39">};</span>
<span class="line" id="L40"></span>
<span class="line" id="L41"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Stream = std.io.StreamSource;</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> EncoderOptions = AllImageFormats.ImageEncoderOptions;</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> AnimationLoopInfinite = -<span class="tok-number">1</span>;</span>
<span class="line" id="L46"></span>
<span class="line" id="L47"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> AnimationFrame = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L48"> pixels: color.PixelStorage,</span>
<span class="line" id="L49"> duration: <span class="tok-type">f32</span>,</span>
<span class="line" id="L50"></span>
<span class="line" id="L51"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: AnimationFrame, allocator: std.mem.Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L52"> self.pixels.deinit(allocator);</span>
<span class="line" id="L53"> }</span>
<span class="line" id="L54">};</span>
<span class="line" id="L55"></span>
<span class="line" id="L56"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Animation = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L57"> frames: FrameList = .{},</span>
<span class="line" id="L58"> loop_count: <span class="tok-type">i32</span> = AnimationLoopInfinite,</span>
<span class="line" id="L59"></span>
<span class="line" id="L60"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> FrameList = std.ArrayListUnmanaged(AnimationFrame);</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Animation, allocator: std.mem.Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L63"> <span class="tok-comment">// Animation share its first frame with the pixels in Image, we don't want to free it twice</span>
</span>
<span class="line" id="L64"> <span class="tok-kw">if</span> (self.frames.items.len &gt;= <span class="tok-number">2</span>) {</span>
<span class="line" id="L65"> <span class="tok-kw">for</span> (self.frames.items[<span class="tok-number">1</span>..]) |frame| {</span>
<span class="line" id="L66"> frame.pixels.deinit(allocator);</span>
<span class="line" id="L67"> }</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> self.frames.deinit(allocator);</span>
<span class="line" id="L71"> }</span>
<span class="line" id="L72">};</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"><span class="tok-comment">/// Format-independant image</span></span>
<span class="line" id="L75">allocator: std.mem.Allocator = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L76">width: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L77">height: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L78">pixels: color.PixelStorage = .{ .invalid = <span class="tok-type">void</span>{} },</span>
<span class="line" id="L79">animation: Animation = .{},</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L82"></span>
<span class="line" id="L83"><span class="tok-kw">const</span> FormatInteraceFnType = *<span class="tok-kw">const</span> <span class="tok-kw">fn</span> () FormatInterface;</span>
<span class="line" id="L84"><span class="tok-kw">const</span> all_interface_funcs = blk: {</span>
<span class="line" id="L85"> <span class="tok-kw">const</span> allFormatDecls = std.meta.declarations(AllImageFormats);</span>
<span class="line" id="L86"> <span class="tok-kw">var</span> result: [allFormatDecls.len]FormatInteraceFnType = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L87"> <span class="tok-kw">var</span> index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L88"> <span class="tok-kw">for</span> (allFormatDecls) |decl| {</span>
<span class="line" id="L89"> <span class="tok-kw">const</span> decl_value = <span class="tok-builtin">@field</span>(AllImageFormats, decl.name);</span>
<span class="line" id="L90"> <span class="tok-kw">const</span> entry_type = <span class="tok-builtin">@TypeOf</span>(decl_value);</span>
<span class="line" id="L91"> <span class="tok-kw">if</span> (entry_type == <span class="tok-type">type</span>) {</span>
<span class="line" id="L92"> <span class="tok-kw">const</span> entryTypeInfo = <span class="tok-builtin">@typeInfo</span>(decl_value);</span>
<span class="line" id="L93"> <span class="tok-kw">if</span> (entryTypeInfo == .Struct) {</span>
<span class="line" id="L94"> <span class="tok-kw">for</span> (entryTypeInfo.Struct.decls) |structEntry| {</span>
<span class="line" id="L95"> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, structEntry.name, <span class="tok-str">&quot;formatInterface&quot;</span>)) {</span>
<span class="line" id="L96"> result[index] = <span class="tok-builtin">@field</span>(decl_value, structEntry.name);</span>
<span class="line" id="L97"> index += <span class="tok-number">1</span>;</span>
<span class="line" id="L98"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L99"> }</span>
<span class="line" id="L100"> }</span>
<span class="line" id="L101"> }</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103"> }</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"> <span class="tok-kw">break</span> :blk result[<span class="tok-number">0</span>..index];</span>
<span class="line" id="L106">};</span>
<span class="line" id="L107"></span>
<span class="line" id="L108"><span class="tok-comment">/// Init an empty image with no pixel data</span></span>
<span class="line" id="L109"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(allocator: std.mem.Allocator) Image {</span>
<span class="line" id="L110"> <span class="tok-kw">return</span> Image{</span>
<span class="line" id="L111"> .allocator = allocator,</span>
<span class="line" id="L112"> };</span>
<span class="line" id="L113">}</span>
<span class="line" id="L114"></span>
<span class="line" id="L115"><span class="tok-comment">/// Deinit the image</span></span>
<span class="line" id="L116"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Image) <span class="tok-type">void</span> {</span>
<span class="line" id="L117"> self.pixels.deinit(self.allocator);</span>
<span class="line" id="L118"> self.animation.deinit(self.allocator);</span>
<span class="line" id="L119">}</span>
<span class="line" id="L120"></span>
<span class="line" id="L121"><span class="tok-comment">/// Load an image from a file path</span></span>
<span class="line" id="L122"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">fromFilePath</span>(allocator: std.mem.Allocator, file_path: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !Image {</span>
<span class="line" id="L123"> <span class="tok-kw">var</span> file = <span class="tok-kw">try</span> std.fs.cwd().openFile(file_path, .{});</span>
<span class="line" id="L124"> <span class="tok-kw">defer</span> file.close();</span>
<span class="line" id="L125"></span>
<span class="line" id="L126"> <span class="tok-kw">return</span> fromFile(allocator, &amp;file);</span>
<span class="line" id="L127">}</span>
<span class="line" id="L128"></span>
<span class="line" id="L129"><span class="tok-comment">/// Load an image from a standard library std.fs.File</span></span>
<span class="line" id="L130"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">fromFile</span>(allocator: std.mem.Allocator, file: *std.fs.File) !Image {</span>
<span class="line" id="L131"> <span class="tok-kw">var</span> stream_source = std.io.StreamSource{ .file = file.* };</span>
<span class="line" id="L132"> <span class="tok-kw">return</span> internalRead(allocator, &amp;stream_source);</span>
<span class="line" id="L133">}</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"><span class="tok-comment">/// Load an image from a memory buffer</span></span>
<span class="line" id="L136"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">fromMemory</span>(allocator: std.mem.Allocator, buffer: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !Image {</span>
<span class="line" id="L137"> <span class="tok-kw">var</span> stream_source = std.io.StreamSource{ .const_buffer = std.io.fixedBufferStream(buffer) };</span>
<span class="line" id="L138"> <span class="tok-kw">return</span> internalRead(allocator, &amp;stream_source);</span>
<span class="line" id="L139">}</span>
<span class="line" id="L140"></span>
<span class="line" id="L141"><span class="tok-comment">/// Create a pixel surface from scratch</span></span>
<span class="line" id="L142"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">create</span>(allocator: std.mem.Allocator, width: <span class="tok-type">usize</span>, height: <span class="tok-type">usize</span>, pixel_format: PixelFormat) !Image {</span>
<span class="line" id="L143"> <span class="tok-kw">const</span> result = Image{</span>
<span class="line" id="L144"> .allocator = allocator,</span>
<span class="line" id="L145"> .width = width,</span>
<span class="line" id="L146"> .height = height,</span>
<span class="line" id="L147"> .pixels = <span class="tok-kw">try</span> color.PixelStorage.init(allocator, pixel_format, width * height),</span>
<span class="line" id="L148"> };</span>
<span class="line" id="L149"></span>
<span class="line" id="L150"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L151">}</span>
<span class="line" id="L152"></span>
<span class="line" id="L153"><span class="tok-comment">/// Return the pixel format of the image</span></span>
<span class="line" id="L154"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pixelFormat</span>(self: Image) PixelFormat {</span>
<span class="line" id="L155"> <span class="tok-kw">return</span> std.meta.activeTag(self.pixels);</span>
<span class="line" id="L156">}</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"><span class="tok-comment">/// Return the pixel data as a const byte slice. In case of an animation, it return the pixel data of the first frame.</span></span>
<span class="line" id="L159"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">rawBytes</span>(self: Image) []<span class="tok-kw">const</span> <span class="tok-type">u8</span> {</span>
<span class="line" id="L160"> <span class="tok-kw">return</span> self.pixels.asBytes();</span>
<span class="line" id="L161">}</span>
<span class="line" id="L162"></span>
<span class="line" id="L163"><span class="tok-comment">/// Return the byte size of a row in the image</span></span>
<span class="line" id="L164"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">rowByteSize</span>(self: Image) <span class="tok-type">usize</span> {</span>
<span class="line" id="L165"> <span class="tok-kw">return</span> self.imageByteSize() / self.height;</span>
<span class="line" id="L166">}</span>
<span class="line" id="L167"></span>
<span class="line" id="L168"><span class="tok-comment">/// Return the byte size of the whole image</span></span>
<span class="line" id="L169"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">imageByteSize</span>(self: Image) <span class="tok-type">usize</span> {</span>
<span class="line" id="L170"> <span class="tok-kw">return</span> self.rawBytes().len;</span>
<span class="line" id="L171">}</span>
<span class="line" id="L172"></span>
<span class="line" id="L173"><span class="tok-comment">/// Is this image is an animation?</span></span>
<span class="line" id="L174"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAnimation</span>(self: Image) <span class="tok-type">bool</span> {</span>
<span class="line" id="L175"> <span class="tok-kw">return</span> self.animation.frames.items.len &gt; <span class="tok-number">0</span>;</span>
<span class="line" id="L176">}</span>
<span class="line" id="L177"></span>
<span class="line" id="L178"><span class="tok-comment">/// Write the image to an image format to the specified path</span></span>
<span class="line" id="L179"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeToFilePath</span>(self: Image, file_path: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, encoder_options: EncoderOptions) WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L180"> <span class="tok-kw">var</span> file = <span class="tok-kw">try</span> std.fs.cwd().createFile(file_path, .{});</span>
<span class="line" id="L181"> <span class="tok-kw">defer</span> file.close();</span>
<span class="line" id="L182"></span>
<span class="line" id="L183"> <span class="tok-kw">try</span> self.writeToFile(file, encoder_options);</span>
<span class="line" id="L184">}</span>
<span class="line" id="L185"></span>
<span class="line" id="L186"><span class="tok-comment">/// Write the image to an image format to the specified std.fs.File</span></span>
<span class="line" id="L187"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeToFile</span>(self: Image, file: std.fs.File, encoder_options: EncoderOptions) WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L188"> <span class="tok-kw">var</span> stream_source = std.io.StreamSource{ .file = file };</span>
<span class="line" id="L189"></span>
<span class="line" id="L190"> <span class="tok-kw">try</span> self.internalWrite(&amp;stream_source, encoder_options);</span>
<span class="line" id="L191">}</span>
<span class="line" id="L192"></span>
<span class="line" id="L193"><span class="tok-comment">/// Write the image to an image format in a memory buffer. The memory buffer is not grown</span></span>
<span class="line" id="L194"><span class="tok-comment">/// for you so make sure you pass a large enough buffer.</span></span>
<span class="line" id="L195"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeToMemory</span>(self: Image, write_buffer: []<span class="tok-type">u8</span>, encoder_options: EncoderOptions) WriteError![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L196"> <span class="tok-kw">var</span> stream_source = std.io.StreamSource{ .buffer = std.io.fixedBufferStream(write_buffer) };</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-kw">try</span> self.internalWrite(&amp;stream_source, encoder_options);</span>
<span class="line" id="L199"></span>
<span class="line" id="L200"> <span class="tok-kw">return</span> stream_source.buffer.getWritten();</span>
<span class="line" id="L201">}</span>
<span class="line" id="L202"></span>
<span class="line" id="L203"><span class="tok-comment">/// Iterate the pixel in pixel-format agnostic way. In the case of an animation, it returns an iterator for the first frame. The iterator is read-only.</span></span>
<span class="line" id="L204"><span class="tok-comment">// FIXME: *const Image is a workaround for a stage2 bug because determining the pass a parameter by value or pointer depending of the size is not mature yet</span>
</span>
<span class="line" id="L205"><span class="tok-comment">// and fails. For now we are explictly requesting to access only a const pointer.</span>
</span>
<span class="line" id="L206"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">iterator</span>(self: *<span class="tok-kw">const</span> Image) color.PixelStorageIterator {</span>
<span class="line" id="L207"> <span class="tok-kw">return</span> color.PixelStorageIterator.init(&amp;self.pixels);</span>
<span class="line" id="L208">}</span>
<span class="line" id="L209"></span>
<span class="line" id="L210"><span class="tok-kw">fn</span> <span class="tok-fn">internalRead</span>(allocator: std.mem.Allocator, stream: *Stream) !Image {</span>
<span class="line" id="L211"> <span class="tok-kw">const</span> format_interface = <span class="tok-kw">try</span> findImageInterfaceFromStream(stream);</span>
<span class="line" id="L212"></span>
<span class="line" id="L213"> <span class="tok-kw">try</span> stream.seekTo(<span class="tok-number">0</span>);</span>
<span class="line" id="L214"></span>
<span class="line" id="L215"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> format_interface.readImage(allocator, stream);</span>
<span class="line" id="L216">}</span>
<span class="line" id="L217"></span>
<span class="line" id="L218"><span class="tok-kw">fn</span> <span class="tok-fn">internalWrite</span>(self: Image, stream: *Stream, encoder_options: EncoderOptions) WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L219"> <span class="tok-kw">const</span> image_format = std.meta.activeTag(encoder_options);</span>
<span class="line" id="L220"></span>
<span class="line" id="L221"> <span class="tok-kw">var</span> format_interface = <span class="tok-kw">try</span> findImageInterfaceFromImageFormat(image_format);</span>
<span class="line" id="L222"></span>
<span class="line" id="L223"> <span class="tok-kw">try</span> format_interface.writeImage(self.allocator, stream, self, encoder_options);</span>
<span class="line" id="L224">}</span>
<span class="line" id="L225"></span>
<span class="line" id="L226"><span class="tok-kw">fn</span> <span class="tok-fn">findImageInterfaceFromStream</span>(stream: *Stream) !FormatInterface {</span>
<span class="line" id="L227"> <span class="tok-kw">for</span> (all_interface_funcs) |intefaceFn| {</span>
<span class="line" id="L228"> <span class="tok-kw">const</span> formatInterface = intefaceFn();</span>
<span class="line" id="L229"></span>
<span class="line" id="L230"> <span class="tok-kw">try</span> stream.seekTo(<span class="tok-number">0</span>);</span>
<span class="line" id="L231"> <span class="tok-kw">const</span> found = <span class="tok-kw">try</span> formatInterface.formatDetect(stream);</span>
<span class="line" id="L232"> <span class="tok-kw">if</span> (found) {</span>
<span class="line" id="L233"> <span class="tok-kw">return</span> formatInterface;</span>
<span class="line" id="L234"> }</span>
<span class="line" id="L235"> }</span>
<span class="line" id="L236"></span>
<span class="line" id="L237"> <span class="tok-kw">return</span> Error.Unsupported;</span>
<span class="line" id="L238">}</span>
<span class="line" id="L239"></span>
<span class="line" id="L240"><span class="tok-kw">fn</span> <span class="tok-fn">findImageInterfaceFromImageFormat</span>(image_format: Format) !FormatInterface {</span>
<span class="line" id="L241"> <span class="tok-kw">for</span> (all_interface_funcs) |interface_fn| {</span>
<span class="line" id="L242"> <span class="tok-kw">const</span> format_interface = interface_fn();</span>
<span class="line" id="L243"></span>
<span class="line" id="L244"> <span class="tok-kw">if</span> (format_interface.format() == image_format) {</span>
<span class="line" id="L245"> <span class="tok-kw">return</span> format_interface;</span>
<span class="line" id="L246"> }</span>
<span class="line" id="L247"> }</span>
<span class="line" id="L248"></span>
<span class="line" id="L249"> <span class="tok-kw">return</span> Error.Unsupported;</span>
<span class="line" id="L250">}</span>
<span class="line" id="L251"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,372 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/buffered_stream_source.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> DefaultBufferSize = <span class="tok-number">8</span> * <span class="tok-number">1024</span>;</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> DefaultBufferedStreamSourceReader = BufferedStreamSourceReader(DefaultBufferSize);</span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> DefaultBufferedStreamSourceWriter = BufferedStreamSourceWriter(DefaultBufferSize);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-comment">// An buffered stream that can read and seek StreamSource</span>
</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">BufferedStreamSourceReader</span>(<span class="tok-kw">comptime</span> BufferSize: <span class="tok-type">usize</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L10"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L11"> buffered_reader: std.io.BufferedReader(BufferSize, std.io.StreamSource.Reader),</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> ReadError = std.io.StreamSource.ReadError;</span>
<span class="line" id="L14"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> SeekError = std.io.StreamSource.SeekError;</span>
<span class="line" id="L15"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> GetSeekPosError = std.io.StreamSource.GetSeekPosError;</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Reader = std.io.Reader(*Self, ReadError, read);</span>
<span class="line" id="L20"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> SeekableStream = std.io.SeekableStream(</span>
<span class="line" id="L21"> *Self,</span>
<span class="line" id="L22"> SeekError,</span>
<span class="line" id="L23"> GetSeekPosError,</span>
<span class="line" id="L24"> seekTo,</span>
<span class="line" id="L25"> seekBy,</span>
<span class="line" id="L26"> getPos,</span>
<span class="line" id="L27"> getEndPos,</span>
<span class="line" id="L28"> );</span>
<span class="line" id="L29"></span>
<span class="line" id="L30"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(self: *Self, dest: []<span class="tok-type">u8</span>) ReadError!<span class="tok-type">usize</span> {</span>
<span class="line" id="L31"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.buffered_reader.unbuffered_reader.context.*) {</span>
<span class="line" id="L32"> .buffer =&gt; |*actual_reader| actual_reader.read(dest),</span>
<span class="line" id="L33"> .const_buffer =&gt; |*actual_reader| actual_reader.read(dest),</span>
<span class="line" id="L34"> .file =&gt; self.buffered_reader.read(dest),</span>
<span class="line" id="L35"> };</span>
<span class="line" id="L36"> }</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekTo</span>(self: *Self, pos: <span class="tok-type">u64</span>) SeekError!<span class="tok-type">void</span> {</span>
<span class="line" id="L39"> <span class="tok-kw">switch</span> (self.buffered_reader.unbuffered_reader.context.*) {</span>
<span class="line" id="L40"> .buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L41"> <span class="tok-kw">return</span> actual_reader.seekTo(pos);</span>
<span class="line" id="L42"> },</span>
<span class="line" id="L43"> .const_buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L44"> <span class="tok-kw">return</span> actual_reader.seekTo(pos);</span>
<span class="line" id="L45"> },</span>
<span class="line" id="L46"> .file =&gt; {</span>
<span class="line" id="L47"> <span class="tok-kw">try</span> self.buffered_reader.unbuffered_reader.context.seekTo(pos);</span>
<span class="line" id="L48"> self.resetBufferedReader();</span>
<span class="line" id="L49"> },</span>
<span class="line" id="L50"> }</span>
<span class="line" id="L51"> }</span>
<span class="line" id="L52"></span>
<span class="line" id="L53"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekBy</span>(self: *Self, amt: <span class="tok-type">i64</span>) SeekError!<span class="tok-type">void</span> {</span>
<span class="line" id="L54"> <span class="tok-kw">switch</span> (self.buffered_reader.unbuffered_reader.context.*) {</span>
<span class="line" id="L55"> .buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L56"> <span class="tok-kw">return</span> actual_reader.seekBy(amt);</span>
<span class="line" id="L57"> },</span>
<span class="line" id="L58"> .const_buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L59"> <span class="tok-kw">return</span> actual_reader.seekBy(amt);</span>
<span class="line" id="L60"> },</span>
<span class="line" id="L61"> .file =&gt; {</span>
<span class="line" id="L62"> <span class="tok-kw">const</span> bytes_availables = self.buffered_reader.end - self.buffered_reader.start;</span>
<span class="line" id="L63"> <span class="tok-kw">if</span> (amt &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L64"> <span class="tok-kw">if</span> (amt &lt;= bytes_availables) {</span>
<span class="line" id="L65"> self.buffered_reader.start += <span class="tok-builtin">@intCast</span>(amt);</span>
<span class="line" id="L66"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L67"> <span class="tok-kw">try</span> self.buffered_reader.unbuffered_reader.context.seekBy(amt - <span class="tok-builtin">@as</span>(<span class="tok-type">i64</span>, <span class="tok-builtin">@intCast</span>(bytes_availables)));</span>
<span class="line" id="L68"> self.resetBufferedReader();</span>
<span class="line" id="L69"> }</span>
<span class="line" id="L70"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (amt &lt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L71"> <span class="tok-kw">const</span> absolute_amt = <span class="tok-builtin">@abs</span>(amt);</span>
<span class="line" id="L72"> <span class="tok-kw">if</span> (absolute_amt &lt;= self.buffered_reader.start) {</span>
<span class="line" id="L73"> self.buffered_reader.start -%= absolute_amt;</span>
<span class="line" id="L74"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L75"> <span class="tok-kw">try</span> self.buffered_reader.unbuffered_reader.context.seekBy(amt - <span class="tok-builtin">@as</span>(<span class="tok-type">i64</span>, <span class="tok-builtin">@intCast</span>(bytes_availables)));</span>
<span class="line" id="L76"> self.resetBufferedReader();</span>
<span class="line" id="L77"> }</span>
<span class="line" id="L78"> }</span>
<span class="line" id="L79"> },</span>
<span class="line" id="L80"> }</span>
<span class="line" id="L81"> }</span>
<span class="line" id="L82"></span>
<span class="line" id="L83"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getEndPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L84"> <span class="tok-kw">return</span> self.buffered_reader.unbuffered_reader.context.getEndPos();</span>
<span class="line" id="L85"> }</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L88"> <span class="tok-kw">switch</span> (self.buffered_reader.unbuffered_reader.context.*) {</span>
<span class="line" id="L89"> .buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L90"> <span class="tok-kw">return</span> actual_reader.getPos();</span>
<span class="line" id="L91"> },</span>
<span class="line" id="L92"> .const_buffer =&gt; |*actual_reader| {</span>
<span class="line" id="L93"> <span class="tok-kw">return</span> actual_reader.getPos();</span>
<span class="line" id="L94"> },</span>
<span class="line" id="L95"> .file =&gt; {</span>
<span class="line" id="L96"> <span class="tok-kw">if</span> (self.buffered_reader.unbuffered_reader.context.getPos()) |position| {</span>
<span class="line" id="L97"> <span class="tok-kw">return</span> position - (self.buffered_reader.end - self.buffered_reader.start);</span>
<span class="line" id="L98"> } <span class="tok-kw">else</span> |err| {</span>
<span class="line" id="L99"> <span class="tok-kw">return</span> err;</span>
<span class="line" id="L100"> }</span>
<span class="line" id="L101"> },</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103"> }</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">reader</span>(self: *Self) Reader {</span>
<span class="line" id="L106"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L107"> }</span>
<span class="line" id="L108"></span>
<span class="line" id="L109"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekableStream</span>(self: *Self) SeekableStream {</span>
<span class="line" id="L110"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L111"> }</span>
<span class="line" id="L112"></span>
<span class="line" id="L113"> <span class="tok-kw">fn</span> <span class="tok-fn">resetBufferedReader</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L114"> self.buffered_reader.start = <span class="tok-number">0</span>;</span>
<span class="line" id="L115"> self.buffered_reader.end = <span class="tok-number">0</span>;</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"> };</span>
<span class="line" id="L118">}</span>
<span class="line" id="L119"></span>
<span class="line" id="L120"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceReader</span>(stream: *std.io.StreamSource) BufferedStreamSourceReader(DefaultBufferSize) {</span>
<span class="line" id="L121"> <span class="tok-kw">return</span> .{ .buffered_reader = .{ .unbuffered_reader = stream.reader() } };</span>
<span class="line" id="L122">}</span>
<span class="line" id="L123"></span>
<span class="line" id="L124"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceReaderWithSize</span>(<span class="tok-kw">comptime</span> buffer_size: <span class="tok-type">usize</span>, stream: *std.io.StreamSource) BufferedStreamSourceReader(buffer_size) {</span>
<span class="line" id="L125"> <span class="tok-kw">return</span> .{ .buffered_reader = .{ .unbuffered_reader = stream.reader() } };</span>
<span class="line" id="L126">}</span>
<span class="line" id="L127"></span>
<span class="line" id="L128"><span class="tok-comment">// An buffered stream that can writer and seek StreamSource</span>
</span>
<span class="line" id="L129"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">BufferedStreamSourceWriter</span>(<span class="tok-kw">comptime</span> BufferSize: <span class="tok-type">usize</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L130"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L131"> buffered_writer: std.io.BufferedWriter(BufferSize, std.io.StreamSource.Writer),</span>
<span class="line" id="L132"></span>
<span class="line" id="L133"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> WriteError = std.io.StreamSource.WriteError;</span>
<span class="line" id="L134"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> SeekError = std.io.StreamSource.SeekError;</span>
<span class="line" id="L135"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> GetSeekPosError = std.io.StreamSource.GetSeekPosError;</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L138"></span>
<span class="line" id="L139"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Writer = std.io.Writer(*Self, WriteError, write);</span>
<span class="line" id="L140"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> SeekableStream = std.io.SeekableStream(</span>
<span class="line" id="L141"> *Self,</span>
<span class="line" id="L142"> SeekError,</span>
<span class="line" id="L143"> GetSeekPosError,</span>
<span class="line" id="L144"> seekTo,</span>
<span class="line" id="L145"> seekBy,</span>
<span class="line" id="L146"> getPos,</span>
<span class="line" id="L147"> getEndPos,</span>
<span class="line" id="L148"> );</span>
<span class="line" id="L149"></span>
<span class="line" id="L150"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: *Self, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) WriteError!<span class="tok-type">usize</span> {</span>
<span class="line" id="L151"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L152"> .buffer =&gt; |*actual_writer| actual_writer.write(bytes),</span>
<span class="line" id="L153"> .const_buffer =&gt; <span class="tok-kw">error</span>.AccessDenied,</span>
<span class="line" id="L154"> .file =&gt; self.buffered_writer.write(bytes),</span>
<span class="line" id="L155"> };</span>
<span class="line" id="L156"> }</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekTo</span>(self: *Self, pos: <span class="tok-type">u64</span>) SeekError!<span class="tok-type">void</span> {</span>
<span class="line" id="L159"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L160"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L161"> <span class="tok-kw">return</span> actual_writer.seekTo(pos);</span>
<span class="line" id="L162"> },</span>
<span class="line" id="L163"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L164"> <span class="tok-kw">return</span> actual_writer.seekTo(pos);</span>
<span class="line" id="L165"> },</span>
<span class="line" id="L166"> .file =&gt; {</span>
<span class="line" id="L167"> <span class="tok-kw">try</span> self.buffered_writer.flush();</span>
<span class="line" id="L168"> <span class="tok-kw">try</span> self.buffered_writer.buffered_writer.context.seekTo(pos);</span>
<span class="line" id="L169"> },</span>
<span class="line" id="L170"> }</span>
<span class="line" id="L171"> }</span>
<span class="line" id="L172"></span>
<span class="line" id="L173"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekBy</span>(self: *Self, amt: <span class="tok-type">i64</span>) SeekError!<span class="tok-type">void</span> {</span>
<span class="line" id="L174"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L175"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L176"> <span class="tok-kw">return</span> actual_writer.seekBy(amt);</span>
<span class="line" id="L177"> },</span>
<span class="line" id="L178"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L179"> <span class="tok-kw">return</span> actual_writer.seekBy(amt);</span>
<span class="line" id="L180"> },</span>
<span class="line" id="L181"> .file =&gt; {</span>
<span class="line" id="L182"> <span class="tok-kw">if</span> (amt &lt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L183"> <span class="tok-kw">const</span> abs_amt = <span class="tok-builtin">@abs</span>(amt);</span>
<span class="line" id="L184"> <span class="tok-kw">if</span> (abs_amt &lt;= self.buffered_writer.end) {</span>
<span class="line" id="L185"> self.buffered_writer.end -= abs_amt;</span>
<span class="line" id="L186"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L187"> self.buffered_writer.flush() <span class="tok-kw">catch</span> {</span>
<span class="line" id="L188"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unseekable;</span>
<span class="line" id="L189"> };</span>
<span class="line" id="L190"> <span class="tok-kw">try</span> self.buffered_writer.unbuffered_writer.context.seekBy(amt);</span>
<span class="line" id="L191"> }</span>
<span class="line" id="L192"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L193"> <span class="tok-kw">const</span> amt_usize: <span class="tok-type">usize</span> = <span class="tok-builtin">@intCast</span>(amt);</span>
<span class="line" id="L194"></span>
<span class="line" id="L195"> <span class="tok-kw">if</span> (self.buffered_writer.end + amt_usize &lt; self.buffered_writer.buf.len) {</span>
<span class="line" id="L196"> self.buffered_writer.end += amt_usize;</span>
<span class="line" id="L197"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L198"> self.buffered_writer.flush() <span class="tok-kw">catch</span> {</span>
<span class="line" id="L199"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unseekable;</span>
<span class="line" id="L200"> };</span>
<span class="line" id="L201"> <span class="tok-kw">try</span> self.buffered_writer.unbuffered_writer.context.seekBy(amt);</span>
<span class="line" id="L202"> }</span>
<span class="line" id="L203"> }</span>
<span class="line" id="L204"> },</span>
<span class="line" id="L205"> }</span>
<span class="line" id="L206"> }</span>
<span class="line" id="L207"></span>
<span class="line" id="L208"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getEndPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L209"> <span class="tok-kw">return</span> self.buffered_writer.unbuffered_writer.context.getEndPos();</span>
<span class="line" id="L210"> }</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPos</span>(self: *Self) GetSeekPosError!<span class="tok-type">u64</span> {</span>
<span class="line" id="L213"> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L214"> .buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L215"> <span class="tok-kw">return</span> actual_writer.getPos();</span>
<span class="line" id="L216"> },</span>
<span class="line" id="L217"> .const_buffer =&gt; |*actual_writer| {</span>
<span class="line" id="L218"> <span class="tok-kw">return</span> actual_writer.getPos();</span>
<span class="line" id="L219"> },</span>
<span class="line" id="L220"> .file =&gt; {</span>
<span class="line" id="L221"> <span class="tok-kw">if</span> (self.buffered_writer.unbuffered_writer.context.getPos()) |position| {</span>
<span class="line" id="L222"> <span class="tok-kw">return</span> position + self.buffered_writer.end;</span>
<span class="line" id="L223"> } <span class="tok-kw">else</span> |err| {</span>
<span class="line" id="L224"> <span class="tok-kw">return</span> err;</span>
<span class="line" id="L225"> }</span>
<span class="line" id="L226"> },</span>
<span class="line" id="L227"> }</span>
<span class="line" id="L228"> }</span>
<span class="line" id="L229"></span>
<span class="line" id="L230"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writer</span>(self: *Self) Writer {</span>
<span class="line" id="L231"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L232"> }</span>
<span class="line" id="L233"></span>
<span class="line" id="L234"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">seekableStream</span>(self: *Self) SeekableStream {</span>
<span class="line" id="L235"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L236"> }</span>
<span class="line" id="L237"></span>
<span class="line" id="L238"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">flush</span>(self: *Self) WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L239"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.buffered_writer.unbuffered_writer.context.*) {</span>
<span class="line" id="L240"> .file =&gt; self.buffered_writer.flush(),</span>
<span class="line" id="L241"> <span class="tok-kw">else</span> =&gt; {},</span>
<span class="line" id="L242"> };</span>
<span class="line" id="L243"> }</span>
<span class="line" id="L244"> };</span>
<span class="line" id="L245">}</span>
<span class="line" id="L246"></span>
<span class="line" id="L247"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceWriter</span>(stream: *std.io.StreamSource) BufferedStreamSourceWriter(DefaultBufferSize) {</span>
<span class="line" id="L248"> <span class="tok-kw">return</span> .{ .buffered_writer = .{ .unbuffered_writer = stream.writer() } };</span>
<span class="line" id="L249">}</span>
<span class="line" id="L250"></span>
<span class="line" id="L251"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bufferedStreamSourceWriterWithSize</span>(<span class="tok-kw">comptime</span> buffer_size: <span class="tok-type">usize</span>, stream: *std.io.StreamSource) BufferedStreamSourceWriter(buffer_size) {</span>
<span class="line" id="L252"> <span class="tok-kw">return</span> .{ .buffered_writer = .{ .unbuffered_writer = stream.writer() } };</span>
<span class="line" id="L253">}</span>
<span class="line" id="L254"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,295 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/compressions/lzw.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>);</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-comment">// Implement a variable code size LZW decoder with support for clear code and end of information code required for GIF decoding</span>
</span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">Decoder</span>(<span class="tok-kw">comptime</span> endian: std.builtin.Endian) <span class="tok-type">type</span> {</span>
<span class="line" id="L6"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L7"> area_allocator: std.heap.ArenaAllocator,</span>
<span class="line" id="L8"> code_size: <span class="tok-type">u8</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L9"> clear_code: <span class="tok-type">u13</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L10"> initial_code_size: <span class="tok-type">u8</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L11"> end_information_code: <span class="tok-type">u13</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L12"> next_code: <span class="tok-type">u13</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L13"> previous_code: ?<span class="tok-type">u13</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L14"> dictionary: std.AutoArrayHashMap(<span class="tok-type">u13</span>, []<span class="tok-kw">const</span> <span class="tok-type">u8</span>),</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"> remaining_data: ?<span class="tok-type">u13</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L17"> remaining_bits: <span class="tok-type">u4</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"> <span class="tok-kw">const</span> MaxCodeSize = <span class="tok-number">12</span>;</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L22"></span>
<span class="line" id="L23"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(allocator: std.mem.Allocator, initial_code_size: <span class="tok-type">u8</span>) !Self {</span>
<span class="line" id="L24"> <span class="tok-kw">var</span> result = Self{</span>
<span class="line" id="L25"> .area_allocator = std.heap.ArenaAllocator.init(allocator),</span>
<span class="line" id="L26"> .code_size = initial_code_size,</span>
<span class="line" id="L27"> .dictionary = std.AutoArrayHashMap(<span class="tok-type">u13</span>, []<span class="tok-kw">const</span> <span class="tok-type">u8</span>).init(allocator),</span>
<span class="line" id="L28"> .initial_code_size = initial_code_size,</span>
<span class="line" id="L29"> .clear_code = <span class="tok-builtin">@as</span>(<span class="tok-type">u13</span>, <span class="tok-number">1</span>) &lt;&lt; <span class="tok-builtin">@intCast</span>(initial_code_size),</span>
<span class="line" id="L30"> .end_information_code = (<span class="tok-builtin">@as</span>(<span class="tok-type">u13</span>, <span class="tok-number">1</span>) &lt;&lt; <span class="tok-builtin">@intCast</span>(initial_code_size)) + <span class="tok-number">1</span>,</span>
<span class="line" id="L31"> .next_code = (<span class="tok-builtin">@as</span>(<span class="tok-type">u13</span>, <span class="tok-number">1</span>) &lt;&lt; <span class="tok-builtin">@intCast</span>(initial_code_size)) + <span class="tok-number">2</span>,</span>
<span class="line" id="L32"> };</span>
<span class="line" id="L33"></span>
<span class="line" id="L34"> <span class="tok-comment">// Reset dictionary and code to its default state</span>
</span>
<span class="line" id="L35"> <span class="tok-kw">try</span> result.resetDictionary();</span>
<span class="line" id="L36"></span>
<span class="line" id="L37"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L38"> }</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L41"> self.area_allocator.deinit();</span>
<span class="line" id="L42"> self.dictionary.deinit();</span>
<span class="line" id="L43"> }</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">decode</span>(self: *Self, reader: Image.Stream.Reader, writer: <span class="tok-kw">anytype</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L46"> <span class="tok-kw">var</span> bit_reader = std.io.bitReader(endian, reader);</span>
<span class="line" id="L47"></span>
<span class="line" id="L48"> <span class="tok-kw">var</span> bits_to_read = self.code_size + <span class="tok-number">1</span>;</span>
<span class="line" id="L49"></span>
<span class="line" id="L50"> <span class="tok-kw">var</span> read_size: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L51"> <span class="tok-kw">var</span> read_code: <span class="tok-type">u13</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L52"></span>
<span class="line" id="L53"> <span class="tok-kw">if</span> (self.remaining_data) |remaining_data| {</span>
<span class="line" id="L54"> <span class="tok-kw">const</span> rest_of_data = <span class="tok-kw">try</span> bit_reader.readBits(<span class="tok-type">u13</span>, self.remaining_bits, &amp;read_size);</span>
<span class="line" id="L55"> <span class="tok-kw">if</span> (read_size &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L56"> <span class="tok-kw">switch</span> (endian) {</span>
<span class="line" id="L57"> .little =&gt; {</span>
<span class="line" id="L58"> read_code = remaining_data | (rest_of_data &lt;&lt; <span class="tok-builtin">@as</span>(<span class="tok-type">u4</span>, <span class="tok-builtin">@intCast</span>(bits_to_read - self.remaining_bits)));</span>
<span class="line" id="L59"> },</span>
<span class="line" id="L60"> .big =&gt; {</span>
<span class="line" id="L61"> read_code = (remaining_data &lt;&lt; self.remaining_bits) | rest_of_data;</span>
<span class="line" id="L62"> },</span>
<span class="line" id="L63"> }</span>
<span class="line" id="L64"> }</span>
<span class="line" id="L65"> self.remaining_data = <span class="tok-null">null</span>;</span>
<span class="line" id="L66"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L67"> read_code = <span class="tok-kw">try</span> bit_reader.readBits(<span class="tok-type">u13</span>, bits_to_read, &amp;read_size);</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-kw">var</span> allocator = self.area_allocator.allocator();</span>
<span class="line" id="L71"></span>
<span class="line" id="L72"> <span class="tok-kw">while</span> (read_size &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L73"> <span class="tok-kw">if</span> (self.dictionary.get(read_code)) |value| {</span>
<span class="line" id="L74"> _ = <span class="tok-kw">try</span> writer.write(value);</span>
<span class="line" id="L75"></span>
<span class="line" id="L76"> <span class="tok-kw">if</span> (self.previous_code) |previous_code| {</span>
<span class="line" id="L77"> <span class="tok-kw">if</span> (self.dictionary.get(previous_code)) |previous_value| {</span>
<span class="line" id="L78"> <span class="tok-kw">var</span> new_value = <span class="tok-kw">try</span> allocator.alloc(<span class="tok-type">u8</span>, previous_value.len + <span class="tok-number">1</span>);</span>
<span class="line" id="L79"> std.mem.copyForwards(<span class="tok-type">u8</span>, new_value, previous_value);</span>
<span class="line" id="L80"> new_value[previous_value.len] = value[<span class="tok-number">0</span>];</span>
<span class="line" id="L81"> <span class="tok-kw">try</span> self.dictionary.put(self.next_code, new_value);</span>
<span class="line" id="L82"></span>
<span class="line" id="L83"> self.next_code += <span class="tok-number">1</span>;</span>
<span class="line" id="L84"></span>
<span class="line" id="L85"> <span class="tok-kw">const</span> max_code = <span class="tok-builtin">@as</span>(<span class="tok-type">u13</span>, <span class="tok-number">1</span>) &lt;&lt; <span class="tok-builtin">@intCast</span>(self.code_size + <span class="tok-number">1</span>);</span>
<span class="line" id="L86"> <span class="tok-kw">if</span> (self.next_code == max_code <span class="tok-kw">and</span> (self.code_size + <span class="tok-number">1</span>) &lt; MaxCodeSize) {</span>
<span class="line" id="L87"> self.code_size += <span class="tok-number">1</span>;</span>
<span class="line" id="L88"> bits_to_read += <span class="tok-number">1</span>;</span>
<span class="line" id="L89"> }</span>
<span class="line" id="L90"> }</span>
<span class="line" id="L91"> }</span>
<span class="line" id="L92"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L93"> <span class="tok-kw">if</span> (read_code == self.clear_code) {</span>
<span class="line" id="L94"> <span class="tok-kw">try</span> self.resetDictionary();</span>
<span class="line" id="L95"> bits_to_read = self.code_size + <span class="tok-number">1</span>;</span>
<span class="line" id="L96"> self.previous_code = read_code;</span>
<span class="line" id="L97"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (read_code == self.end_information_code) {</span>
<span class="line" id="L98"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L99"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L100"> <span class="tok-kw">if</span> (self.previous_code) |previous_code| {</span>
<span class="line" id="L101"> <span class="tok-kw">if</span> (self.dictionary.get(previous_code)) |previous_value| {</span>
<span class="line" id="L102"> <span class="tok-kw">var</span> new_value = <span class="tok-kw">try</span> allocator.alloc(<span class="tok-type">u8</span>, previous_value.len + <span class="tok-number">1</span>);</span>
<span class="line" id="L103"> std.mem.copyForwards(<span class="tok-type">u8</span>, new_value, previous_value);</span>
<span class="line" id="L104"> new_value[previous_value.len] = previous_value[<span class="tok-number">0</span>];</span>
<span class="line" id="L105"> <span class="tok-kw">try</span> self.dictionary.put(self.next_code, new_value);</span>
<span class="line" id="L106"></span>
<span class="line" id="L107"> _ = <span class="tok-kw">try</span> writer.write(new_value);</span>
<span class="line" id="L108"></span>
<span class="line" id="L109"> self.next_code += <span class="tok-number">1</span>;</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"> <span class="tok-kw">const</span> max_code = <span class="tok-builtin">@as</span>(<span class="tok-type">u13</span>, <span class="tok-number">1</span>) &lt;&lt; <span class="tok-builtin">@intCast</span>(self.code_size + <span class="tok-number">1</span>);</span>
<span class="line" id="L112"> <span class="tok-kw">if</span> (self.next_code == max_code <span class="tok-kw">and</span> (self.code_size + <span class="tok-number">1</span>) &lt; MaxCodeSize) {</span>
<span class="line" id="L113"> self.code_size += <span class="tok-number">1</span>;</span>
<span class="line" id="L114"> bits_to_read += <span class="tok-number">1</span>;</span>
<span class="line" id="L115"> }</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"> }</span>
<span class="line" id="L118"> }</span>
<span class="line" id="L119"> }</span>
<span class="line" id="L120"></span>
<span class="line" id="L121"> self.previous_code = read_code;</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"> read_code = <span class="tok-kw">try</span> bit_reader.readBits(<span class="tok-type">u13</span>, bits_to_read, &amp;read_size);</span>
<span class="line" id="L124"> <span class="tok-kw">if</span> (read_size != bits_to_read) {</span>
<span class="line" id="L125"> self.remaining_data = read_code;</span>
<span class="line" id="L126"> self.remaining_bits = <span class="tok-builtin">@intCast</span>(bits_to_read - read_size);</span>
<span class="line" id="L127"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L128"> }</span>
<span class="line" id="L129"> }</span>
<span class="line" id="L130"> }</span>
<span class="line" id="L131"></span>
<span class="line" id="L132"> <span class="tok-kw">fn</span> <span class="tok-fn">resetDictionary</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L133"> self.dictionary.clearRetainingCapacity();</span>
<span class="line" id="L134"> self.area_allocator.deinit();</span>
<span class="line" id="L135"></span>
<span class="line" id="L136"> self.code_size = self.initial_code_size;</span>
<span class="line" id="L137"> self.next_code = (<span class="tok-builtin">@as</span>(<span class="tok-type">u13</span>, <span class="tok-number">1</span>) &lt;&lt; <span class="tok-builtin">@intCast</span>(self.initial_code_size)) + <span class="tok-number">2</span>;</span>
<span class="line" id="L138"></span>
<span class="line" id="L139"> self.area_allocator = std.heap.ArenaAllocator.init(self.area_allocator.child_allocator);</span>
<span class="line" id="L140"> <span class="tok-kw">var</span> allocator = self.area_allocator.allocator();</span>
<span class="line" id="L141"></span>
<span class="line" id="L142"> <span class="tok-kw">const</span> roots_size = <span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">1</span>) &lt;&lt; <span class="tok-builtin">@intCast</span>(self.code_size);</span>
<span class="line" id="L143"></span>
<span class="line" id="L144"> <span class="tok-kw">var</span> index: <span class="tok-type">u13</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L145"></span>
<span class="line" id="L146"> <span class="tok-kw">while</span> (index &lt; roots_size) : (index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L147"> <span class="tok-kw">var</span> data = <span class="tok-kw">try</span> allocator.alloc(<span class="tok-type">u8</span>, <span class="tok-number">1</span>);</span>
<span class="line" id="L148"> data[<span class="tok-number">0</span>] = <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@truncate</span>(index));</span>
<span class="line" id="L149"></span>
<span class="line" id="L150"> <span class="tok-kw">try</span> self.dictionary.put(index, data);</span>
<span class="line" id="L151"> }</span>
<span class="line" id="L152"> }</span>
<span class="line" id="L153"> };</span>
<span class="line" id="L154">}</span>
<span class="line" id="L155"></span>
<span class="line" id="L156"><span class="tok-kw">test</span> <span class="tok-str">&quot;Should decode a simple LZW little-endian stream&quot;</span> {</span>
<span class="line" id="L157"> <span class="tok-kw">const</span> initial_code_size = <span class="tok-number">2</span>;</span>
<span class="line" id="L158"> <span class="tok-kw">const</span> test_data = [_]<span class="tok-type">u8</span>{ <span class="tok-number">0x4c</span>, <span class="tok-number">0x01</span> };</span>
<span class="line" id="L159"></span>
<span class="line" id="L160"> <span class="tok-kw">var</span> reader = Image.Stream{</span>
<span class="line" id="L161"> .const_buffer = std.io.fixedBufferStream(&amp;test_data),</span>
<span class="line" id="L162"> };</span>
<span class="line" id="L163"></span>
<span class="line" id="L164"> <span class="tok-kw">var</span> out_data_storage: [<span class="tok-number">256</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L165"> <span class="tok-kw">var</span> out_data_buffer = Image.Stream{</span>
<span class="line" id="L166"> .buffer = std.io.fixedBufferStream(&amp;out_data_storage),</span>
<span class="line" id="L167"> };</span>
<span class="line" id="L168"></span>
<span class="line" id="L169"> <span class="tok-kw">var</span> lzw = <span class="tok-kw">try</span> Decoder(.little).init(std.testing.allocator, initial_code_size);</span>
<span class="line" id="L170"> <span class="tok-kw">defer</span> lzw.deinit();</span>
<span class="line" id="L171"></span>
<span class="line" id="L172"> <span class="tok-kw">try</span> lzw.decode(reader.reader(), out_data_buffer.writer());</span>
<span class="line" id="L173"></span>
<span class="line" id="L174"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">1</span>), out_data_buffer.buffer.pos);</span>
<span class="line" id="L175"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-number">1</span>), out_data_storage[<span class="tok-number">0</span>]);</span>
<span class="line" id="L176">}</span>
<span class="line" id="L177"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,142 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/all.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BMP = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;bmp.zig&quot;</span>).BMP;</span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> GIF = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;gif.zig&quot;</span>).GIF;</span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> JPEG = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;jpeg.zig&quot;</span>).JPEG;</span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PBM = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;netpbm.zig&quot;</span>).PBM;</span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PCX = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;pcx.zig&quot;</span>).PCX;</span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PGM = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;netpbm.zig&quot;</span>).PGM;</span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PNG = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;png.zig&quot;</span>).PNG;</span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PPM = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;netpbm.zig&quot;</span>).PPM;</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> QOI = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;qoi.zig&quot;</span>).QOI;</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> TGA = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tga.zig&quot;</span>).TGA;</span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PAM = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;pam.zig&quot;</span>).PAM;</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ImageEncoderOptions = <span class="tok-kw">union</span>(<span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>).Format) {</span>
<span class="line" id="L14"> bmp: BMP.EncoderOptions,</span>
<span class="line" id="L15"> gif: <span class="tok-type">void</span>,</span>
<span class="line" id="L16"> jpg: <span class="tok-type">void</span>,</span>
<span class="line" id="L17"> pbm: PBM.EncoderOptions,</span>
<span class="line" id="L18"> pcx: PCX.EncoderOptions,</span>
<span class="line" id="L19"> pgm: PGM.EncoderOptions,</span>
<span class="line" id="L20"> png: PNG.EncoderOptions,</span>
<span class="line" id="L21"> ppm: PPM.EncoderOptions,</span>
<span class="line" id="L22"> qoi: QOI.EncoderOptions,</span>
<span class="line" id="L23"> tga: TGA.EncoderOptions,</span>
<span class="line" id="L24"> pam: PAM.EncoderOptions,</span>
<span class="line" id="L25">};</span>
<span class="line" id="L26"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,544 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/bmp.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../color.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> utils = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../utils.zig&quot;</span>);</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> BitmapMagicHeader = [_]<span class="tok-type">u8</span>{ <span class="tok-str">'B'</span>, <span class="tok-str">'M'</span> };</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BitmapFileHeader = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L12"> magic_header: [<span class="tok-number">2</span>]<span class="tok-type">u8</span> = BitmapMagicHeader,</span>
<span class="line" id="L13"> size: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L14"> reserved: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L15"> pixel_offset: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L16">};</span>
<span class="line" id="L17"></span>
<span class="line" id="L18"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CompressionMethod = <span class="tok-kw">enum</span>(<span class="tok-type">u32</span>) {</span>
<span class="line" id="L19"> none = <span class="tok-number">0</span>,</span>
<span class="line" id="L20"> rle8 = <span class="tok-number">1</span>,</span>
<span class="line" id="L21"> rle4 = <span class="tok-number">2</span>,</span>
<span class="line" id="L22"> bitfields = <span class="tok-number">3</span>,</span>
<span class="line" id="L23"> jpg = <span class="tok-number">4</span>,</span>
<span class="line" id="L24"> png = <span class="tok-number">5</span>,</span>
<span class="line" id="L25"> alpha_bit_fields = <span class="tok-number">6</span>,</span>
<span class="line" id="L26"> cmyk = <span class="tok-number">11</span>,</span>
<span class="line" id="L27"> cmyk_rle8 = <span class="tok-number">12</span>,</span>
<span class="line" id="L28"> cmyk_rle4 = <span class="tok-number">13</span>,</span>
<span class="line" id="L29">};</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BitmapColorSpace = <span class="tok-kw">enum</span>(<span class="tok-type">u32</span>) {</span>
<span class="line" id="L32"> calibrated_rgb = <span class="tok-number">0</span>,</span>
<span class="line" id="L33"> srgb = utils.toMagicNumber(<span class="tok-str">&quot;sRGB&quot;</span>, .big),</span>
<span class="line" id="L34"> windows_color_space = utils.toMagicNumber(<span class="tok-str">&quot;Win &quot;</span>, .big),</span>
<span class="line" id="L35"> profile_linked = utils.toMagicNumber(<span class="tok-str">&quot;LINK&quot;</span>, .big),</span>
<span class="line" id="L36"> profile_embedded = utils.toMagicNumber(<span class="tok-str">&quot;MBED&quot;</span>, .big),</span>
<span class="line" id="L37">};</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BitmapIntent = <span class="tok-kw">enum</span>(<span class="tok-type">u32</span>) {</span>
<span class="line" id="L40"> business = <span class="tok-number">1</span>,</span>
<span class="line" id="L41"> graphics = <span class="tok-number">2</span>,</span>
<span class="line" id="L42"> images = <span class="tok-number">4</span>,</span>
<span class="line" id="L43"> absolute_colorimetric = <span class="tok-number">8</span>,</span>
<span class="line" id="L44">};</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CieXyz = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L47"> x: <span class="tok-type">u32</span> = <span class="tok-number">0</span>, <span class="tok-comment">// TODO: Use FXPT2DOT30</span>
</span>
<span class="line" id="L48"> y: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L49"> z: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L50">};</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CieXyzTriple = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L53"> red: CieXyz = CieXyz{},</span>
<span class="line" id="L54"> green: CieXyz = CieXyz{},</span>
<span class="line" id="L55"> blue: CieXyz = CieXyz{},</span>
<span class="line" id="L56">};</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BitmapInfoHeaderWindows31 = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L59"> header_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L60"> width: <span class="tok-type">i32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L61"> height: <span class="tok-type">i32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L62"> color_plane: <span class="tok-type">u16</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L63"> bit_count: <span class="tok-type">u16</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L64"> compression_method: CompressionMethod = .none,</span>
<span class="line" id="L65"> image_raw_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L66"> horizontal_resolution: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L67"> vertical_resolution: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L68"> palette_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L69"> important_colors: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L70"></span>
<span class="line" id="L71"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> HeaderSize = <span class="tok-builtin">@sizeOf</span>(BitmapInfoHeaderWindows31);</span>
<span class="line" id="L72">};</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BitmapInfoHeaderV4 = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L75"> header_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L76"> width: <span class="tok-type">i32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L77"> height: <span class="tok-type">i32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L78"> color_plane: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L79"> bit_count: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L80"> compression_method: CompressionMethod = .none,</span>
<span class="line" id="L81"> image_raw_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L82"> horizontal_resolution: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L83"> vertical_resolution: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L84"> palette_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L85"> important_colors: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L86"> red_mask: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L87"> green_mask: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L88"> blue_mask: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L89"> alpha_mask: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L90"> color_space: BitmapColorSpace = .srgb,</span>
<span class="line" id="L91"> cie_end_points: CieXyzTriple = .{},</span>
<span class="line" id="L92"> gamma_red: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L93"> gamma_green: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L94"> gamma_blue: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L95"></span>
<span class="line" id="L96"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> HeaderSize = <span class="tok-builtin">@sizeOf</span>(BitmapInfoHeaderV4);</span>
<span class="line" id="L97">};</span>
<span class="line" id="L98"></span>
<span class="line" id="L99"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BitmapInfoHeaderV5 = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L100"> header_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L101"> width: <span class="tok-type">i32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L102"> height: <span class="tok-type">i32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L103"> color_plane: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L104"> bit_count: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L105"> compression_method: CompressionMethod = .none,</span>
<span class="line" id="L106"> image_raw_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L107"> horizontal_resolution: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L108"> vertical_resolution: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L109"> palette_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L110"> important_colors: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L111"> red_mask: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L112"> green_mask: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L113"> blue_mask: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L114"> alpha_mask: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L115"> color_space: BitmapColorSpace = .srgb,</span>
<span class="line" id="L116"> cie_end_points: CieXyzTriple = .{},</span>
<span class="line" id="L117"> gamma_red: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L118"> gamma_green: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L119"> gamma_blue: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L120"> intent: BitmapIntent = .graphics,</span>
<span class="line" id="L121"> profile_data: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L122"> profile_size: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L123"> reserved: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L124"></span>
<span class="line" id="L125"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> HeaderSize = <span class="tok-builtin">@sizeOf</span>(BitmapInfoHeaderV5);</span>
<span class="line" id="L126">};</span>
<span class="line" id="L127"></span>
<span class="line" id="L128"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BitmapInfoHeader = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L129"> windows31: BitmapInfoHeaderWindows31,</span>
<span class="line" id="L130"> v4: BitmapInfoHeaderV4,</span>
<span class="line" id="L131"> v5: BitmapInfoHeaderV5,</span>
<span class="line" id="L132">};</span>
<span class="line" id="L133"></span>
<span class="line" id="L134"><span class="tok-comment">// Print resolution of the image,</span>
</span>
<span class="line" id="L135"><span class="tok-comment">// 72 DPI × 39.3701 inches per metre yields 2834.6472</span>
</span>
<span class="line" id="L136"><span class="tok-kw">const</span> PixelsPerMeterResolution = <span class="tok-number">2835</span>;</span>
<span class="line" id="L137"></span>
<span class="line" id="L138"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> BMP = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L139"> file_header: BitmapFileHeader = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L140"> info_header: BitmapInfoHeader = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L141"></span>
<span class="line" id="L142"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> EncoderOptions = <span class="tok-kw">struct</span> {};</span>
<span class="line" id="L143"></span>
<span class="line" id="L144"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatInterface</span>() FormatInterface {</span>
<span class="line" id="L145"> <span class="tok-kw">return</span> FormatInterface{</span>
<span class="line" id="L146"> .format = format,</span>
<span class="line" id="L147"> .formatDetect = formatDetect,</span>
<span class="line" id="L148"> .readImage = readImage,</span>
<span class="line" id="L149"> .writeImage = writeImage,</span>
<span class="line" id="L150"> };</span>
<span class="line" id="L151"> }</span>
<span class="line" id="L152"></span>
<span class="line" id="L153"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">format</span>() Image.Format {</span>
<span class="line" id="L154"> <span class="tok-kw">return</span> Image.Format.bmp;</span>
<span class="line" id="L155"> }</span>
<span class="line" id="L156"></span>
<span class="line" id="L157"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatDetect</span>(stream: *Image.Stream) Image.Stream.ReadError!<span class="tok-type">bool</span> {</span>
<span class="line" id="L158"> <span class="tok-kw">var</span> magic_number_buffer: [<span class="tok-number">2</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L159"> _ = <span class="tok-kw">try</span> stream.read(magic_number_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L160"> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, magic_number_buffer[<span class="tok-number">0</span>..], BitmapMagicHeader[<span class="tok-number">0</span>..])) {</span>
<span class="line" id="L161"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L162"> }</span>
<span class="line" id="L163"></span>
<span class="line" id="L164"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L165"> }</span>
<span class="line" id="L166"></span>
<span class="line" id="L167"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readImage</span>(allocator: std.mem.Allocator, stream: *Image.Stream) Image.ReadError!Image {</span>
<span class="line" id="L168"> <span class="tok-kw">var</span> result = Image.init(allocator);</span>
<span class="line" id="L169"> <span class="tok-kw">errdefer</span> result.deinit();</span>
<span class="line" id="L170"></span>
<span class="line" id="L171"> <span class="tok-kw">var</span> bmp = BMP{};</span>
<span class="line" id="L172"> <span class="tok-kw">const</span> pixels = <span class="tok-kw">try</span> bmp.read(allocator, stream);</span>
<span class="line" id="L173"></span>
<span class="line" id="L174"> result.width = <span class="tok-builtin">@intCast</span>(bmp.width());</span>
<span class="line" id="L175"> result.height = <span class="tok-builtin">@intCast</span>(bmp.height());</span>
<span class="line" id="L176"> result.pixels = pixels;</span>
<span class="line" id="L177"></span>
<span class="line" id="L178"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L179"> }</span>
<span class="line" id="L180"></span>
<span class="line" id="L181"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(allocator: std.mem.Allocator, stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L182"> <span class="tok-kw">var</span> bmp = BMP{};</span>
<span class="line" id="L183"></span>
<span class="line" id="L184"> <span class="tok-comment">// Fill header information based on pixel format</span>
</span>
<span class="line" id="L185"> <span class="tok-kw">switch</span> (image.pixels) {</span>
<span class="line" id="L186"> .bgr24 =&gt; {</span>
<span class="line" id="L187"> bmp.file_header = .{</span>
<span class="line" id="L188"> .size = <span class="tok-builtin">@intCast</span>(image.width * image.height * <span class="tok-number">3</span> + <span class="tok-builtin">@sizeOf</span>(BitmapFileHeader) + BitmapInfoHeaderV4.HeaderSize),</span>
<span class="line" id="L189"> .pixel_offset = <span class="tok-builtin">@sizeOf</span>(BitmapFileHeader) + BitmapInfoHeaderV4.HeaderSize,</span>
<span class="line" id="L190"> };</span>
<span class="line" id="L191"></span>
<span class="line" id="L192"> bmp.info_header = .{</span>
<span class="line" id="L193"> .v4 = .{</span>
<span class="line" id="L194"> .header_size = BitmapInfoHeaderV4.HeaderSize,</span>
<span class="line" id="L195"> .width = <span class="tok-builtin">@intCast</span>(image.width),</span>
<span class="line" id="L196"> .height = <span class="tok-builtin">@intCast</span>(image.height),</span>
<span class="line" id="L197"> .color_plane = <span class="tok-number">1</span>,</span>
<span class="line" id="L198"> .bit_count = <span class="tok-number">24</span>,</span>
<span class="line" id="L199"> .compression_method = .none,</span>
<span class="line" id="L200"> .image_raw_size = <span class="tok-builtin">@intCast</span>(image.width * image.height * <span class="tok-number">3</span>),</span>
<span class="line" id="L201"> .horizontal_resolution = PixelsPerMeterResolution,</span>
<span class="line" id="L202"> .vertical_resolution = PixelsPerMeterResolution,</span>
<span class="line" id="L203"> .color_space = .srgb,</span>
<span class="line" id="L204"> },</span>
<span class="line" id="L205"> };</span>
<span class="line" id="L206"> },</span>
<span class="line" id="L207"> .bgra32 =&gt; {</span>
<span class="line" id="L208"> bmp.file_header = .{</span>
<span class="line" id="L209"> .size = <span class="tok-builtin">@intCast</span>(image.width * image.height * <span class="tok-number">4</span> + <span class="tok-builtin">@sizeOf</span>(BitmapFileHeader) + BitmapInfoHeaderV5.HeaderSize),</span>
<span class="line" id="L210"> .pixel_offset = <span class="tok-builtin">@sizeOf</span>(BitmapFileHeader) + BitmapInfoHeaderV5.HeaderSize,</span>
<span class="line" id="L211"> };</span>
<span class="line" id="L212"></span>
<span class="line" id="L213"> bmp.info_header = .{</span>
<span class="line" id="L214"> .v5 = .{</span>
<span class="line" id="L215"> .header_size = BitmapInfoHeaderV5.HeaderSize,</span>
<span class="line" id="L216"> .width = <span class="tok-builtin">@intCast</span>(image.width),</span>
<span class="line" id="L217"> .height = <span class="tok-builtin">@intCast</span>(image.height),</span>
<span class="line" id="L218"> .color_plane = <span class="tok-number">1</span>,</span>
<span class="line" id="L219"> .bit_count = <span class="tok-number">32</span>,</span>
<span class="line" id="L220"> .compression_method = .bitfields, <span class="tok-comment">// We must specify the color mask when using an 32-bpp bmp with V5</span>
</span>
<span class="line" id="L221"> .image_raw_size = <span class="tok-builtin">@intCast</span>(image.width * image.height * <span class="tok-number">4</span>),</span>
<span class="line" id="L222"> .horizontal_resolution = PixelsPerMeterResolution,</span>
<span class="line" id="L223"> .vertical_resolution = PixelsPerMeterResolution,</span>
<span class="line" id="L224"> .color_space = .srgb,</span>
<span class="line" id="L225"> .red_mask = <span class="tok-number">0x0000FF00</span>,</span>
<span class="line" id="L226"> .green_mask = <span class="tok-number">0x00FF0000</span>,</span>
<span class="line" id="L227"> .blue_mask = <span class="tok-number">0xFF000000</span>,</span>
<span class="line" id="L228"> .alpha_mask = <span class="tok-number">0x000000FF</span>,</span>
<span class="line" id="L229"> },</span>
<span class="line" id="L230"> };</span>
<span class="line" id="L231"> },</span>
<span class="line" id="L232"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L233"> <span class="tok-kw">return</span> Image.WriteError.InvalidData;</span>
<span class="line" id="L234"> },</span>
<span class="line" id="L235"> }</span>
<span class="line" id="L236"></span>
<span class="line" id="L237"> <span class="tok-kw">try</span> bmp.write(stream, image.pixels);</span>
<span class="line" id="L238"></span>
<span class="line" id="L239"> _ = allocator;</span>
<span class="line" id="L240"> _ = encoder_options;</span>
<span class="line" id="L241"> }</span>
<span class="line" id="L242"></span>
<span class="line" id="L243"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">width</span>(self: BMP) <span class="tok-type">i32</span> {</span>
<span class="line" id="L244"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.info_header) {</span>
<span class="line" id="L245"> .windows31 =&gt; |win31| {</span>
<span class="line" id="L246"> <span class="tok-kw">return</span> win31.width;</span>
<span class="line" id="L247"> },</span>
<span class="line" id="L248"> .v4 =&gt; |v4Header| {</span>
<span class="line" id="L249"> <span class="tok-kw">return</span> v4Header.width;</span>
<span class="line" id="L250"> },</span>
<span class="line" id="L251"> .v5 =&gt; |v5Header| {</span>
<span class="line" id="L252"> <span class="tok-kw">return</span> v5Header.width;</span>
<span class="line" id="L253"> },</span>
<span class="line" id="L254"> };</span>
<span class="line" id="L255"> }</span>
<span class="line" id="L256"></span>
<span class="line" id="L257"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">height</span>(self: BMP) <span class="tok-type">i32</span> {</span>
<span class="line" id="L258"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.info_header) {</span>
<span class="line" id="L259"> .windows31 =&gt; |win31| {</span>
<span class="line" id="L260"> <span class="tok-kw">return</span> win31.height;</span>
<span class="line" id="L261"> },</span>
<span class="line" id="L262"> .v4 =&gt; |v4Header| {</span>
<span class="line" id="L263"> <span class="tok-kw">return</span> v4Header.height;</span>
<span class="line" id="L264"> },</span>
<span class="line" id="L265"> .v5 =&gt; |v5Header| {</span>
<span class="line" id="L266"> <span class="tok-kw">return</span> v5Header.height;</span>
<span class="line" id="L267"> },</span>
<span class="line" id="L268"> };</span>
<span class="line" id="L269"> }</span>
<span class="line" id="L270"></span>
<span class="line" id="L271"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pixelFormat</span>(self: BMP) Image.ReadError!PixelFormat {</span>
<span class="line" id="L272"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.info_header) {</span>
<span class="line" id="L273"> .v4 =&gt; |v4Header| <span class="tok-kw">try</span> findPixelFormat(v4Header.bit_count, v4Header.compression_method),</span>
<span class="line" id="L274"> .v5 =&gt; |v5Header| <span class="tok-kw">try</span> findPixelFormat(v5Header.bit_count, v5Header.compression_method),</span>
<span class="line" id="L275"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> Image.Error.Unsupported,</span>
<span class="line" id="L276"> };</span>
<span class="line" id="L277"> }</span>
<span class="line" id="L278"></span>
<span class="line" id="L279"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(self: *BMP, allocator: std.mem.Allocator, stream: *Image.Stream) Image.ReadError!color.PixelStorage {</span>
<span class="line" id="L280"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceReader(stream);</span>
<span class="line" id="L281"></span>
<span class="line" id="L282"> <span class="tok-comment">// Read file header</span>
</span>
<span class="line" id="L283"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L284"> self.file_header = <span class="tok-kw">try</span> utils.readStruct(reader, BitmapFileHeader, .little);</span>
<span class="line" id="L285"> <span class="tok-kw">if</span> (!std.mem.eql(<span class="tok-type">u8</span>, self.file_header.magic_header[<span class="tok-number">0</span>..], BitmapMagicHeader[<span class="tok-number">0</span>..])) {</span>
<span class="line" id="L286"> <span class="tok-kw">return</span> Image.ReadError.InvalidData;</span>
<span class="line" id="L287"> }</span>
<span class="line" id="L288"></span>
<span class="line" id="L289"> <span class="tok-kw">const</span> header_size = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u32</span>, .little);</span>
<span class="line" id="L290"> <span class="tok-kw">try</span> buffered_stream.seekBy(-<span class="tok-builtin">@sizeOf</span>(<span class="tok-type">u32</span>));</span>
<span class="line" id="L291"></span>
<span class="line" id="L292"> <span class="tok-comment">// Read info header</span>
</span>
<span class="line" id="L293"> self.info_header = <span class="tok-kw">switch</span> (header_size) {</span>
<span class="line" id="L294"> BitmapInfoHeaderWindows31.HeaderSize =&gt; BitmapInfoHeader{ .windows31 = <span class="tok-kw">try</span> utils.readStruct(reader, BitmapInfoHeaderWindows31, .little) },</span>
<span class="line" id="L295"> BitmapInfoHeaderV4.HeaderSize =&gt; BitmapInfoHeader{ .v4 = <span class="tok-kw">try</span> utils.readStruct(reader, BitmapInfoHeaderV4, .little) },</span>
<span class="line" id="L296"> BitmapInfoHeaderV5.HeaderSize =&gt; BitmapInfoHeader{ .v5 = <span class="tok-kw">try</span> utils.readStruct(reader, BitmapInfoHeaderV5, .little) },</span>
<span class="line" id="L297"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> Image.Error.Unsupported,</span>
<span class="line" id="L298"> };</span>
<span class="line" id="L299"></span>
<span class="line" id="L300"> <span class="tok-kw">var</span> pixels: color.PixelStorage = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L301"></span>
<span class="line" id="L302"> <span class="tok-comment">// Read pixel data</span>
</span>
<span class="line" id="L303"> _ = <span class="tok-kw">switch</span> (self.info_header) {</span>
<span class="line" id="L304"> .v4 =&gt; |v4Header| {</span>
<span class="line" id="L305"> <span class="tok-kw">const</span> pixel_width = v4Header.width;</span>
<span class="line" id="L306"> <span class="tok-kw">const</span> pixel_height = v4Header.height;</span>
<span class="line" id="L307"> <span class="tok-kw">const</span> pixel_format = <span class="tok-kw">try</span> findPixelFormat(v4Header.bit_count, v4Header.compression_method);</span>
<span class="line" id="L308"></span>
<span class="line" id="L309"> pixels = <span class="tok-kw">try</span> color.PixelStorage.init(allocator, pixel_format, <span class="tok-builtin">@intCast</span>(pixel_width * pixel_height));</span>
<span class="line" id="L310"> <span class="tok-kw">errdefer</span> pixels.deinit(allocator);</span>
<span class="line" id="L311"></span>
<span class="line" id="L312"> <span class="tok-kw">try</span> readPixels(reader, pixel_width, pixel_height, &amp;pixels);</span>
<span class="line" id="L313"> },</span>
<span class="line" id="L314"> .v5 =&gt; |v5Header| {</span>
<span class="line" id="L315"> <span class="tok-kw">const</span> pixel_width = v5Header.width;</span>
<span class="line" id="L316"> <span class="tok-kw">const</span> pixel_height = v5Header.height;</span>
<span class="line" id="L317"> <span class="tok-kw">const</span> pixel_format = <span class="tok-kw">try</span> findPixelFormat(v5Header.bit_count, v5Header.compression_method);</span>
<span class="line" id="L318"></span>
<span class="line" id="L319"> pixels = <span class="tok-kw">try</span> color.PixelStorage.init(allocator, pixel_format, <span class="tok-builtin">@intCast</span>(pixel_width * pixel_height));</span>
<span class="line" id="L320"> <span class="tok-kw">errdefer</span> pixels.deinit(allocator);</span>
<span class="line" id="L321"></span>
<span class="line" id="L322"> <span class="tok-kw">try</span> readPixels(reader, pixel_width, pixel_height, &amp;pixels);</span>
<span class="line" id="L323"> },</span>
<span class="line" id="L324"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> Image.Error.Unsupported,</span>
<span class="line" id="L325"> };</span>
<span class="line" id="L326"></span>
<span class="line" id="L327"> <span class="tok-kw">return</span> pixels;</span>
<span class="line" id="L328"> }</span>
<span class="line" id="L329"></span>
<span class="line" id="L330"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: BMP, stream: *Image.Stream, pixels: color.PixelStorage) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L331"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceWriter(stream);</span>
<span class="line" id="L332"></span>
<span class="line" id="L333"> <span class="tok-kw">const</span> writer = buffered_stream.writer();</span>
<span class="line" id="L334"></span>
<span class="line" id="L335"> <span class="tok-kw">try</span> utils.writeStruct(writer, self.file_header, .little);</span>
<span class="line" id="L336"></span>
<span class="line" id="L337"> <span class="tok-kw">switch</span> (self.info_header) {</span>
<span class="line" id="L338"> .v4 =&gt; |v4| {</span>
<span class="line" id="L339"> <span class="tok-kw">try</span> utils.writeStruct(writer, v4, .little);</span>
<span class="line" id="L340"> },</span>
<span class="line" id="L341"> .v5 =&gt; |v5| {</span>
<span class="line" id="L342"> <span class="tok-kw">try</span> utils.writeStruct(writer, v5, .little);</span>
<span class="line" id="L343"> },</span>
<span class="line" id="L344"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L345"> <span class="tok-kw">return</span> Image.WriteError.InvalidData;</span>
<span class="line" id="L346"> },</span>
<span class="line" id="L347"> }</span>
<span class="line" id="L348"></span>
<span class="line" id="L349"> <span class="tok-kw">try</span> writePixels(writer, pixels, self.width(), self.height());</span>
<span class="line" id="L350"></span>
<span class="line" id="L351"> <span class="tok-kw">try</span> buffered_stream.flush();</span>
<span class="line" id="L352"> }</span>
<span class="line" id="L353"></span>
<span class="line" id="L354"> <span class="tok-kw">fn</span> <span class="tok-fn">findPixelFormat</span>(bit_count: <span class="tok-type">u32</span>, compression: CompressionMethod) Image.Error!PixelFormat {</span>
<span class="line" id="L355"> <span class="tok-kw">if</span> (bit_count == <span class="tok-number">32</span> <span class="tok-kw">and</span> compression == CompressionMethod.bitfields) {</span>
<span class="line" id="L356"> <span class="tok-kw">return</span> PixelFormat.bgra32;</span>
<span class="line" id="L357"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (bit_count == <span class="tok-number">24</span> <span class="tok-kw">and</span> compression == CompressionMethod.none) {</span>
<span class="line" id="L358"> <span class="tok-kw">return</span> PixelFormat.bgr24;</span>
<span class="line" id="L359"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L360"> <span class="tok-kw">return</span> Image.Error.Unsupported;</span>
<span class="line" id="L361"> }</span>
<span class="line" id="L362"> }</span>
<span class="line" id="L363"></span>
<span class="line" id="L364"> <span class="tok-kw">fn</span> <span class="tok-fn">readPixels</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader, pixel_width: <span class="tok-type">i32</span>, pixel_height: <span class="tok-type">i32</span>, pixels: *color.PixelStorage) Image.ReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L365"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (pixels.*) {</span>
<span class="line" id="L366"> .bgr24 =&gt; {</span>
<span class="line" id="L367"> <span class="tok-kw">return</span> readPixelsInternal(pixels.bgr24, reader, pixel_width, pixel_height);</span>
<span class="line" id="L368"> },</span>
<span class="line" id="L369"> .bgra32 =&gt; {</span>
<span class="line" id="L370"> <span class="tok-kw">return</span> readPixelsInternal(pixels.bgra32, reader, pixel_width, pixel_height);</span>
<span class="line" id="L371"> },</span>
<span class="line" id="L372"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L373"> <span class="tok-kw">return</span> Image.Error.Unsupported;</span>
<span class="line" id="L374"> },</span>
<span class="line" id="L375"> };</span>
<span class="line" id="L376"> }</span>
<span class="line" id="L377"></span>
<span class="line" id="L378"> <span class="tok-kw">fn</span> <span class="tok-fn">readPixelsInternal</span>(pixels: <span class="tok-kw">anytype</span>, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader, pixel_width: <span class="tok-type">i32</span>, pixel_height: <span class="tok-type">i32</span>) Image.ReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L379"> <span class="tok-kw">const</span> ColorBufferType = <span class="tok-builtin">@typeInfo</span>(<span class="tok-builtin">@TypeOf</span>(pixels)).Pointer.child;</span>
<span class="line" id="L380"></span>
<span class="line" id="L381"> <span class="tok-kw">var</span> x: <span class="tok-type">i32</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L382"> <span class="tok-kw">var</span> y: <span class="tok-type">i32</span> = pixel_height - <span class="tok-number">1</span>;</span>
<span class="line" id="L383"> <span class="tok-kw">while</span> (y &gt;= <span class="tok-number">0</span>) : (y -= <span class="tok-number">1</span>) {</span>
<span class="line" id="L384"> <span class="tok-kw">const</span> scanline = y * pixel_width;</span>
<span class="line" id="L385"></span>
<span class="line" id="L386"> x = <span class="tok-number">0</span>;</span>
<span class="line" id="L387"> <span class="tok-kw">while</span> (x &lt; pixel_width) : (x += <span class="tok-number">1</span>) {</span>
<span class="line" id="L388"> pixels[<span class="tok-builtin">@intCast</span>(scanline + x)] = <span class="tok-kw">try</span> utils.readStruct(reader, ColorBufferType, .little);</span>
<span class="line" id="L389"> }</span>
<span class="line" id="L390"> }</span>
<span class="line" id="L391"> }</span>
<span class="line" id="L392"></span>
<span class="line" id="L393"> <span class="tok-kw">fn</span> <span class="tok-fn">writePixels</span>(writer: buffered_stream_source.DefaultBufferedStreamSourceWriter.Writer, pixels: color.PixelStorage, pixel_width: <span class="tok-type">i32</span>, pixel_height: <span class="tok-type">i32</span>) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L394"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L395"> .bgr24 =&gt; {</span>
<span class="line" id="L396"> <span class="tok-kw">return</span> writePixelsInternal(pixels.bgr24, writer, pixel_width, pixel_height);</span>
<span class="line" id="L397"> },</span>
<span class="line" id="L398"> .bgra32 =&gt; {</span>
<span class="line" id="L399"> <span class="tok-kw">return</span> writePixelsInternal(pixels.bgra32, writer, pixel_width, pixel_height);</span>
<span class="line" id="L400"> },</span>
<span class="line" id="L401"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L402"> <span class="tok-kw">return</span> Image.WriteError.InvalidData;</span>
<span class="line" id="L403"> },</span>
<span class="line" id="L404"> };</span>
<span class="line" id="L405"> }</span>
<span class="line" id="L406"></span>
<span class="line" id="L407"> <span class="tok-kw">fn</span> <span class="tok-fn">writePixelsInternal</span>(pixels: <span class="tok-kw">anytype</span>, writer: buffered_stream_source.DefaultBufferedStreamSourceWriter.Writer, pixel_width: <span class="tok-type">i32</span>, pixel_height: <span class="tok-type">i32</span>) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L408"> <span class="tok-kw">var</span> x: <span class="tok-type">i32</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L409"> <span class="tok-kw">var</span> y: <span class="tok-type">i32</span> = pixel_height - <span class="tok-number">1</span>;</span>
<span class="line" id="L410"> <span class="tok-kw">while</span> (y &gt;= <span class="tok-number">0</span>) : (y -= <span class="tok-number">1</span>) {</span>
<span class="line" id="L411"> <span class="tok-kw">const</span> scanline = y * pixel_width;</span>
<span class="line" id="L412"></span>
<span class="line" id="L413"> x = <span class="tok-number">0</span>;</span>
<span class="line" id="L414"> <span class="tok-kw">while</span> (x &lt; pixel_width) : (x += <span class="tok-number">1</span>) {</span>
<span class="line" id="L415"> <span class="tok-kw">try</span> utils.writeStruct(writer, pixels[<span class="tok-builtin">@intCast</span>(scanline + x)], .little);</span>
<span class="line" id="L416"> }</span>
<span class="line" id="L417"> }</span>
<span class="line" id="L418"> }</span>
<span class="line" id="L419">};</span>
<span class="line" id="L420"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,366 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/jpeg.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> ImageError = Image.Error;</span>
<span class="line" id="L7"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L8"><span class="tok-kw">const</span> ImageWriteError = Image.WriteError;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L11"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../color.zig&quot;</span>);</span>
<span class="line" id="L12"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> FrameHeader = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/FrameHeader.zig&quot;</span>);</span>
<span class="line" id="L15"><span class="tok-kw">const</span> JFIFHeader = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/JFIFHeader.zig&quot;</span>);</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"><span class="tok-kw">const</span> Markers = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/utils.zig&quot;</span>).Markers;</span>
<span class="line" id="L18"><span class="tok-kw">const</span> ZigzagOffsets = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/utils.zig&quot;</span>).ZigzagOffsets;</span>
<span class="line" id="L19"><span class="tok-kw">const</span> IDCTMultipliers = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/utils.zig&quot;</span>).IDCTMultipliers;</span>
<span class="line" id="L20"><span class="tok-kw">const</span> QuantizationTable = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/quantization.zig&quot;</span>).Table;</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"><span class="tok-kw">const</span> HuffmanReader = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/huffman.zig&quot;</span>).Reader;</span>
<span class="line" id="L23"><span class="tok-kw">const</span> HuffmanTable = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/huffman.zig&quot;</span>).Table;</span>
<span class="line" id="L24"><span class="tok-kw">const</span> Frame = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/Frame.zig&quot;</span>);</span>
<span class="line" id="L25"><span class="tok-kw">const</span> Scan = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./jpeg/Scan.zig&quot;</span>);</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"><span class="tok-comment">// TODO: Chroma subsampling</span>
</span>
<span class="line" id="L28"><span class="tok-comment">// TODO: Progressive scans</span>
</span>
<span class="line" id="L29"><span class="tok-comment">// TODO: Non-baseline sequential DCT</span>
</span>
<span class="line" id="L30"><span class="tok-comment">// TODO: Precisions other than 8-bit</span>
</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"><span class="tok-comment">// TODO: Hierarchical mode of JPEG compression.</span>
</span>
<span class="line" id="L33"></span>
<span class="line" id="L34"><span class="tok-kw">const</span> JPEG_DEBUG = <span class="tok-null">false</span>;</span>
<span class="line" id="L35"></span>
<span class="line" id="L36"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> JPEG = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L37"> frame: ?Frame = <span class="tok-null">null</span>,</span>
<span class="line" id="L38"> allocator: Allocator,</span>
<span class="line" id="L39"> quantization_tables: [<span class="tok-number">4</span>]?QuantizationTable,</span>
<span class="line" id="L40"></span>
<span class="line" id="L41"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(allocator: Allocator) JPEG {</span>
<span class="line" id="L42"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L43"> .allocator = allocator,</span>
<span class="line" id="L44"> .quantization_tables = [_]?QuantizationTable{<span class="tok-null">null</span>} ** <span class="tok-number">4</span>,</span>
<span class="line" id="L45"> };</span>
<span class="line" id="L46"> }</span>
<span class="line" id="L47"></span>
<span class="line" id="L48"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *JPEG) <span class="tok-type">void</span> {</span>
<span class="line" id="L49"> <span class="tok-kw">if</span> (self.frame) |*frame| {</span>
<span class="line" id="L50"> frame.deinit();</span>
<span class="line" id="L51"> }</span>
<span class="line" id="L52"> }</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-kw">fn</span> <span class="tok-fn">parseDefineQuantizationTables</span>(self: *JPEG, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L55"> <span class="tok-kw">var</span> segment_size = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L56"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;DefineQuantizationTables: segment size = 0x{X}\n&quot;</span>, .{segment_size});</span>
<span class="line" id="L57"> segment_size -= <span class="tok-number">2</span>;</span>
<span class="line" id="L58"></span>
<span class="line" id="L59"> <span class="tok-kw">while</span> (segment_size &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L60"> <span class="tok-kw">const</span> precision_and_destination = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L61"> <span class="tok-kw">const</span> table_precision = precision_and_destination &gt;&gt; <span class="tok-number">4</span>;</span>
<span class="line" id="L62"> <span class="tok-kw">const</span> table_destination = precision_and_destination &amp; <span class="tok-number">0b11</span>;</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"> <span class="tok-kw">const</span> quantization_table = <span class="tok-kw">try</span> QuantizationTable.read(table_precision, reader);</span>
<span class="line" id="L65"> <span class="tok-kw">switch</span> (quantization_table) {</span>
<span class="line" id="L66"> .q8 =&gt; segment_size -= <span class="tok-number">64</span> + <span class="tok-number">1</span>,</span>
<span class="line" id="L67"> .q16 =&gt; segment_size -= <span class="tok-number">128</span> + <span class="tok-number">1</span>,</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> self.quantization_tables[table_destination] = quantization_table;</span>
<span class="line" id="L71"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot; Table with precision {} installed at {}\n&quot;</span>, .{ table_precision, table_destination });</span>
<span class="line" id="L72"> }</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> <span class="tok-kw">fn</span> <span class="tok-fn">parseScan</span>(self: *JPEG, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader, pixels_opt: *?color.PixelStorage) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L76"> <span class="tok-kw">if</span> (self.frame) |frame| {</span>
<span class="line" id="L77"> <span class="tok-kw">try</span> Scan.performScan(&amp;frame, reader, pixels_opt);</span>
<span class="line" id="L78"> } <span class="tok-kw">else</span> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L79"> }</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"> <span class="tok-kw">fn</span> <span class="tok-fn">initializePixels</span>(self: *JPEG, pixels_opt: *?color.PixelStorage) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L82"> <span class="tok-kw">if</span> (self.frame) |frame| {</span>
<span class="line" id="L83"> <span class="tok-kw">var</span> pixel_format: PixelFormat = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L84"> <span class="tok-kw">switch</span> (frame.frame_header.components.len) {</span>
<span class="line" id="L85"> <span class="tok-number">1</span> =&gt; pixel_format = .grayscale8,</span>
<span class="line" id="L86"> <span class="tok-number">3</span> =&gt; pixel_format = .rgb24,</span>
<span class="line" id="L87"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L88"> }</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> <span class="tok-kw">const</span> pixel_count = <span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-builtin">@intCast</span>(frame.frame_header.samples_per_row)) * <span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-builtin">@intCast</span>(frame.frame_header.row_count));</span>
<span class="line" id="L91"> pixels_opt.* = <span class="tok-kw">try</span> color.PixelStorage.init(self.allocator, pixel_format, pixel_count);</span>
<span class="line" id="L92"> } <span class="tok-kw">else</span> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L93"> }</span>
<span class="line" id="L94"></span>
<span class="line" id="L95"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(self: *JPEG, stream: *Image.Stream, pixels_opt: *?color.PixelStorage) ImageReadError!Frame {</span>
<span class="line" id="L96"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceReader(stream);</span>
<span class="line" id="L97"></span>
<span class="line" id="L98"> <span class="tok-kw">const</span> jfif_header = JFIFHeader.read(&amp;buffered_stream) <span class="tok-kw">catch</span> |err| <span class="tok-kw">switch</span> (err) {</span>
<span class="line" id="L99"> <span class="tok-kw">error</span>.App0MarkerDoesNotExist, <span class="tok-kw">error</span>.JfifIdentifierNotSet, <span class="tok-kw">error</span>.ThumbnailImagesUnsupported, <span class="tok-kw">error</span>.ExtraneousApplicationMarker =&gt; <span class="tok-kw">return</span> ImageReadError.InvalidData,</span>
<span class="line" id="L100"> <span class="tok-kw">else</span> =&gt; |e| <span class="tok-kw">return</span> e,</span>
<span class="line" id="L101"> };</span>
<span class="line" id="L102"> _ = jfif_header;</span>
<span class="line" id="L103"></span>
<span class="line" id="L104"> <span class="tok-kw">errdefer</span> {</span>
<span class="line" id="L105"> <span class="tok-kw">if</span> (pixels_opt.*) |pixels| {</span>
<span class="line" id="L106"> pixels.deinit(self.allocator);</span>
<span class="line" id="L107"> pixels_opt.* = <span class="tok-null">null</span>;</span>
<span class="line" id="L108"> }</span>
<span class="line" id="L109"> }</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L112"> <span class="tok-kw">var</span> marker = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L113"> <span class="tok-kw">while</span> (marker != <span class="tok-builtin">@intFromEnum</span>(Markers.end_of_image)) : (marker = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big)) {</span>
<span class="line" id="L114"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;Parsing marker value: 0x{X}\n&quot;</span>, .{marker});</span>
<span class="line" id="L115"></span>
<span class="line" id="L116"> <span class="tok-kw">if</span> (marker &gt;= <span class="tok-builtin">@intFromEnum</span>(Markers.application0) <span class="tok-kw">and</span> marker &lt; <span class="tok-builtin">@intFromEnum</span>(Markers.application0) + <span class="tok-number">16</span>) {</span>
<span class="line" id="L117"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;Skipping application data segment\n&quot;</span>, .{});</span>
<span class="line" id="L118"> <span class="tok-kw">const</span> application_data_length = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L119"> <span class="tok-kw">try</span> buffered_stream.seekBy(application_data_length - <span class="tok-number">2</span>);</span>
<span class="line" id="L120"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L121"> }</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"> <span class="tok-kw">switch</span> (<span class="tok-builtin">@as</span>(Markers, <span class="tok-builtin">@enumFromInt</span>(marker))) {</span>
<span class="line" id="L124"> <span class="tok-comment">// TODO(angelo): this should be moved inside the frameheader, it's part of thet</span>
</span>
<span class="line" id="L125"> <span class="tok-comment">// and then the header just dispatches correctly what to do with it.</span>
</span>
<span class="line" id="L126"> <span class="tok-comment">// JPEG should be as clear as possible</span>
</span>
<span class="line" id="L127"> .sof0 =&gt; { <span class="tok-comment">// Baseline DCT</span>
</span>
<span class="line" id="L128"> <span class="tok-kw">if</span> (self.frame != <span class="tok-null">null</span>) {</span>
<span class="line" id="L129"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L130"> }</span>
<span class="line" id="L131"></span>
<span class="line" id="L132"> self.frame = <span class="tok-kw">try</span> Frame.read(self.allocator, &amp;self.quantization_tables, &amp;buffered_stream);</span>
<span class="line" id="L133"> },</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"> .sof1 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported, <span class="tok-comment">// extended sequential DCT Huffman coding</span>
</span>
<span class="line" id="L136"> .sof2 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported, <span class="tok-comment">// progressive DCT Huffman coding</span>
</span>
<span class="line" id="L137"> .sof3 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported, <span class="tok-comment">// lossless (sequential) Huffman coding</span>
</span>
<span class="line" id="L138"> .sof5 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L139"> .sof6 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L140"> .sof7 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L141"> .sof9 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported, <span class="tok-comment">// extended sequential DCT arithmetic coding</span>
</span>
<span class="line" id="L142"> .sof10 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported, <span class="tok-comment">// progressive DCT arithmetic coding</span>
</span>
<span class="line" id="L143"> .sof11 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported, <span class="tok-comment">// lossless (sequential) arithmetic coding</span>
</span>
<span class="line" id="L144"> .sof13 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L145"> .sof14 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L146"> .sof15 =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L147"></span>
<span class="line" id="L148"> .start_of_scan =&gt; {</span>
<span class="line" id="L149"> <span class="tok-kw">try</span> self.initializePixels(pixels_opt);</span>
<span class="line" id="L150"> <span class="tok-kw">try</span> self.parseScan(reader, pixels_opt);</span>
<span class="line" id="L151"> },</span>
<span class="line" id="L152"></span>
<span class="line" id="L153"> .define_quantization_tables =&gt; {</span>
<span class="line" id="L154"> <span class="tok-kw">try</span> self.parseDefineQuantizationTables(reader);</span>
<span class="line" id="L155"> },</span>
<span class="line" id="L156"></span>
<span class="line" id="L157"> .comment =&gt; {</span>
<span class="line" id="L158"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;Skipping comment segment\n&quot;</span>, .{});</span>
<span class="line" id="L159"></span>
<span class="line" id="L160"> <span class="tok-kw">const</span> comment_length = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L161"> <span class="tok-kw">try</span> buffered_stream.seekBy(comment_length - <span class="tok-number">2</span>);</span>
<span class="line" id="L162"> },</span>
<span class="line" id="L163"></span>
<span class="line" id="L164"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L165"> <span class="tok-comment">// TODO(angelo): raise invalid marker, more precise error.</span>
</span>
<span class="line" id="L166"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L167"> },</span>
<span class="line" id="L168"> }</span>
<span class="line" id="L169"> }</span>
<span class="line" id="L170"></span>
<span class="line" id="L171"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (self.frame) |frame| frame <span class="tok-kw">else</span> ImageReadError.InvalidData;</span>
<span class="line" id="L172"> }</span>
<span class="line" id="L173"></span>
<span class="line" id="L174"> <span class="tok-comment">// Format interface</span>
</span>
<span class="line" id="L175"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatInterface</span>() FormatInterface {</span>
<span class="line" id="L176"> <span class="tok-kw">return</span> FormatInterface{</span>
<span class="line" id="L177"> .format = format,</span>
<span class="line" id="L178"> .formatDetect = formatDetect,</span>
<span class="line" id="L179"> .readImage = readImage,</span>
<span class="line" id="L180"> .writeImage = writeImage,</span>
<span class="line" id="L181"> };</span>
<span class="line" id="L182"> }</span>
<span class="line" id="L183"></span>
<span class="line" id="L184"> <span class="tok-kw">fn</span> <span class="tok-fn">format</span>() Image.Format {</span>
<span class="line" id="L185"> <span class="tok-kw">return</span> Image.Format.jpg;</span>
<span class="line" id="L186"> }</span>
<span class="line" id="L187"></span>
<span class="line" id="L188"> <span class="tok-kw">fn</span> <span class="tok-fn">formatDetect</span>(stream: *Image.Stream) ImageReadError!<span class="tok-type">bool</span> {</span>
<span class="line" id="L189"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceReader(stream);</span>
<span class="line" id="L190"></span>
<span class="line" id="L191"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L192"> <span class="tok-kw">const</span> maybe_start_of_image = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L193"> <span class="tok-kw">if</span> (maybe_start_of_image != <span class="tok-builtin">@intFromEnum</span>(Markers.start_of_image)) {</span>
<span class="line" id="L194"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L195"> }</span>
<span class="line" id="L196"></span>
<span class="line" id="L197"> <span class="tok-kw">try</span> buffered_stream.seekTo(<span class="tok-number">6</span>);</span>
<span class="line" id="L198"> <span class="tok-kw">var</span> identifier_buffer: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L199"> _ = <span class="tok-kw">try</span> buffered_stream.read(identifier_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L200"></span>
<span class="line" id="L201"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, identifier_buffer[<span class="tok-number">0</span>..], <span class="tok-str">&quot;JFIF&quot;</span>);</span>
<span class="line" id="L202"> }</span>
<span class="line" id="L203"></span>
<span class="line" id="L204"> <span class="tok-kw">fn</span> <span class="tok-fn">readImage</span>(allocator: Allocator, stream: *Image.Stream) ImageReadError!Image {</span>
<span class="line" id="L205"> <span class="tok-kw">var</span> result = Image.init(allocator);</span>
<span class="line" id="L206"> <span class="tok-kw">errdefer</span> result.deinit();</span>
<span class="line" id="L207"> <span class="tok-kw">var</span> jpeg = JPEG.init(allocator);</span>
<span class="line" id="L208"> <span class="tok-kw">defer</span> jpeg.deinit();</span>
<span class="line" id="L209"></span>
<span class="line" id="L210"> <span class="tok-kw">var</span> pixels_opt: ?color.PixelStorage = <span class="tok-null">null</span>;</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> <span class="tok-kw">const</span> frame = <span class="tok-kw">try</span> jpeg.read(stream, &amp;pixels_opt);</span>
<span class="line" id="L213"></span>
<span class="line" id="L214"> result.width = frame.frame_header.samples_per_row;</span>
<span class="line" id="L215"> result.height = frame.frame_header.row_count;</span>
<span class="line" id="L216"></span>
<span class="line" id="L217"> <span class="tok-kw">if</span> (pixels_opt) |pixels| {</span>
<span class="line" id="L218"> result.pixels = pixels;</span>
<span class="line" id="L219"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L220"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L221"> }</span>
<span class="line" id="L222"></span>
<span class="line" id="L223"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L224"> }</span>
<span class="line" id="L225"></span>
<span class="line" id="L226"> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(allocator: Allocator, write_stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L227"> _ = allocator;</span>
<span class="line" id="L228"> _ = write_stream;</span>
<span class="line" id="L229"> _ = image;</span>
<span class="line" id="L230"> _ = encoder_options;</span>
<span class="line" id="L231"> }</span>
<span class="line" id="L232">};</span>
<span class="line" id="L233"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,375 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/jpeg/Frame.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../Image.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">const</span> Markers = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).Markers;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> FrameHeader = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;FrameHeader.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> QuantizationTable = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;quantization.zig&quot;</span>).Table;</span>
<span class="line" id="L11"><span class="tok-kw">const</span> HuffmanTable = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;huffman.zig&quot;</span>).Table;</span>
<span class="line" id="L12"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../color.zig&quot;</span>);</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> IDCTMultipliers = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).IDCTMultipliers;</span>
<span class="line" id="L15"><span class="tok-kw">const</span> MAX_COMPONENTS = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).MAX_COMPONENTS;</span>
<span class="line" id="L16"><span class="tok-kw">const</span> MAX_BLOCKS = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).MAX_BLOCKS;</span>
<span class="line" id="L17"><span class="tok-kw">const</span> MCU = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).MCU;</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"><span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L20">allocator: Allocator,</span>
<span class="line" id="L21">frame_header: FrameHeader,</span>
<span class="line" id="L22">quantization_tables: *[<span class="tok-number">4</span>]?QuantizationTable,</span>
<span class="line" id="L23">dc_huffman_tables: [<span class="tok-number">2</span>]?HuffmanTable,</span>
<span class="line" id="L24">ac_huffman_tables: [<span class="tok-number">2</span>]?HuffmanTable,</span>
<span class="line" id="L25"></span>
<span class="line" id="L26"><span class="tok-kw">const</span> JPEG_DEBUG = <span class="tok-null">false</span>;</span>
<span class="line" id="L27"></span>
<span class="line" id="L28"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(allocator: Allocator, quantization_tables: *[<span class="tok-number">4</span>]?QuantizationTable, buffered_stream: *buffered_stream_source.DefaultBufferedStreamSourceReader) ImageReadError!Self {</span>
<span class="line" id="L29"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L30"> <span class="tok-kw">const</span> frame_header = <span class="tok-kw">try</span> FrameHeader.read(allocator, reader);</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"> <span class="tok-kw">var</span> self = Self{</span>
<span class="line" id="L33"> .allocator = allocator,</span>
<span class="line" id="L34"> .frame_header = frame_header,</span>
<span class="line" id="L35"> .quantization_tables = quantization_tables,</span>
<span class="line" id="L36"> .dc_huffman_tables = [_]?HuffmanTable{<span class="tok-null">null</span>} ** <span class="tok-number">2</span>,</span>
<span class="line" id="L37"> .ac_huffman_tables = [_]?HuffmanTable{<span class="tok-null">null</span>} ** <span class="tok-number">2</span>,</span>
<span class="line" id="L38"> };</span>
<span class="line" id="L39"> <span class="tok-kw">errdefer</span> self.deinit();</span>
<span class="line" id="L40"></span>
<span class="line" id="L41"> <span class="tok-kw">var</span> marker = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L42"> <span class="tok-kw">while</span> (marker != <span class="tok-builtin">@intFromEnum</span>(Markers.start_of_scan)) : (marker = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big)) {</span>
<span class="line" id="L43"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;Frame: Parsing marker value: 0x{X}\n&quot;</span>, .{marker});</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"> <span class="tok-kw">switch</span> (<span class="tok-builtin">@as</span>(Markers, <span class="tok-builtin">@enumFromInt</span>(marker))) {</span>
<span class="line" id="L46"> .define_huffman_tables =&gt; {</span>
<span class="line" id="L47"> <span class="tok-kw">try</span> self.parseDefineHuffmanTables(reader);</span>
<span class="line" id="L48"> },</span>
<span class="line" id="L49"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L50"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L51"> },</span>
<span class="line" id="L52"> }</span>
<span class="line" id="L53"> }</span>
<span class="line" id="L54"></span>
<span class="line" id="L55"> <span class="tok-comment">// Undo the last marker read</span>
</span>
<span class="line" id="L56"> <span class="tok-kw">try</span> buffered_stream.seekBy(-<span class="tok-number">2</span>);</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"> <span class="tok-kw">return</span> self;</span>
<span class="line" id="L59">}</span>
<span class="line" id="L60"></span>
<span class="line" id="L61"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L62"> <span class="tok-kw">for</span> (&amp;self.dc_huffman_tables) |*maybe_huffman_table| {</span>
<span class="line" id="L63"> <span class="tok-kw">if</span> (maybe_huffman_table.*) |*huffman_table| {</span>
<span class="line" id="L64"> huffman_table.deinit();</span>
<span class="line" id="L65"> }</span>
<span class="line" id="L66"> }</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"> <span class="tok-kw">for</span> (&amp;self.ac_huffman_tables) |*maybe_huffman_table| {</span>
<span class="line" id="L69"> <span class="tok-kw">if</span> (maybe_huffman_table.*) |*huffman_table| {</span>
<span class="line" id="L70"> huffman_table.deinit();</span>
<span class="line" id="L71"> }</span>
<span class="line" id="L72"> }</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"> self.frame_header.deinit();</span>
<span class="line" id="L75">}</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"><span class="tok-kw">fn</span> <span class="tok-fn">parseDefineHuffmanTables</span>(self: *Self, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L78"> <span class="tok-kw">var</span> segment_size = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L79"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;DefineHuffmanTables: segment size = 0x{X}\n&quot;</span>, .{segment_size});</span>
<span class="line" id="L80"> segment_size -= <span class="tok-number">2</span>;</span>
<span class="line" id="L81"></span>
<span class="line" id="L82"> <span class="tok-kw">while</span> (segment_size &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L83"> <span class="tok-kw">const</span> class_and_destination = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L84"> <span class="tok-kw">const</span> table_class = class_and_destination &gt;&gt; <span class="tok-number">4</span>;</span>
<span class="line" id="L85"> <span class="tok-kw">const</span> table_destination = class_and_destination &amp; <span class="tok-number">0b1</span>;</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-kw">const</span> huffman_table = <span class="tok-kw">try</span> HuffmanTable.read(self.allocator, table_class, reader);</span>
<span class="line" id="L88"></span>
<span class="line" id="L89"> <span class="tok-kw">if</span> (table_class == <span class="tok-number">0</span>) {</span>
<span class="line" id="L90"> <span class="tok-kw">if</span> (self.dc_huffman_tables[table_destination]) |*old_huffman_table| {</span>
<span class="line" id="L91"> old_huffman_table.deinit();</span>
<span class="line" id="L92"> }</span>
<span class="line" id="L93"> self.dc_huffman_tables[table_destination] = huffman_table;</span>
<span class="line" id="L94"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L95"> <span class="tok-kw">if</span> (self.ac_huffman_tables[table_destination]) |*old_huffman_table| {</span>
<span class="line" id="L96"> old_huffman_table.deinit();</span>
<span class="line" id="L97"> }</span>
<span class="line" id="L98"> self.ac_huffman_tables[table_destination] = huffman_table;</span>
<span class="line" id="L99"> }</span>
<span class="line" id="L100"></span>
<span class="line" id="L101"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot; Table with class {} installed at {}\n&quot;</span>, .{ table_class, table_destination });</span>
<span class="line" id="L102"></span>
<span class="line" id="L103"> <span class="tok-comment">// Class+Destination + code counts + code table</span>
</span>
<span class="line" id="L104"> segment_size -= <span class="tok-number">1</span> + <span class="tok-number">16</span> + <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intCast</span>(huffman_table.code_map.count()));</span>
<span class="line" id="L105"> }</span>
<span class="line" id="L106">}</span>
<span class="line" id="L107"></span>
<span class="line" id="L108"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">renderToPixels</span>(self: *<span class="tok-kw">const</span> Self, mcu_storage: *[MAX_COMPONENTS][MAX_BLOCKS]MCU, mcu_id: <span class="tok-type">usize</span>, pixels: *color.PixelStorage) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L109"> <span class="tok-kw">switch</span> (self.frame_header.components.len) {</span>
<span class="line" id="L110"> <span class="tok-number">1</span> =&gt; <span class="tok-kw">try</span> self.renderToPixelsGrayscale(&amp;mcu_storage[<span class="tok-number">0</span>][<span class="tok-number">0</span>], mcu_id, pixels.grayscale8), <span class="tok-comment">// Grayscale images is non-interleaved</span>
</span>
<span class="line" id="L111"> <span class="tok-number">3</span> =&gt; <span class="tok-kw">try</span> self.renderToPixelsRgb(mcu_storage, mcu_id, pixels.rgb24),</span>
<span class="line" id="L112"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L113"> }</span>
<span class="line" id="L114">}</span>
<span class="line" id="L115"></span>
<span class="line" id="L116"><span class="tok-kw">fn</span> <span class="tok-fn">renderToPixelsGrayscale</span>(self: *<span class="tok-kw">const</span> Self, mcu_storage: *MCU, mcu_id: <span class="tok-type">usize</span>, pixels: []color.Grayscale8) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L117"> <span class="tok-kw">const</span> mcu_width = <span class="tok-number">8</span>;</span>
<span class="line" id="L118"> <span class="tok-kw">const</span> mcu_height = <span class="tok-number">8</span>;</span>
<span class="line" id="L119"> <span class="tok-kw">const</span> width = self.frame_header.samples_per_row;</span>
<span class="line" id="L120"> <span class="tok-kw">const</span> height = pixels.len / width;</span>
<span class="line" id="L121"> <span class="tok-kw">const</span> mcus_per_row = (width + mcu_width - <span class="tok-number">1</span>) / mcu_width;</span>
<span class="line" id="L122"> <span class="tok-kw">const</span> mcu_origin_x = (mcu_id % mcus_per_row) * mcu_width;</span>
<span class="line" id="L123"> <span class="tok-kw">const</span> mcu_origin_y = (mcu_id / mcus_per_row) * mcu_height;</span>
<span class="line" id="L124"></span>
<span class="line" id="L125"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..mcu_height) |mcu_y| {</span>
<span class="line" id="L126"> <span class="tok-kw">const</span> y = mcu_origin_y + mcu_y;</span>
<span class="line" id="L127"> <span class="tok-kw">if</span> (y &gt;= height) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L128"></span>
<span class="line" id="L129"> <span class="tok-comment">// y coordinates in the block</span>
</span>
<span class="line" id="L130"> <span class="tok-kw">const</span> block_y = mcu_y % <span class="tok-number">8</span>;</span>
<span class="line" id="L131"></span>
<span class="line" id="L132"> <span class="tok-kw">const</span> stride = y * width;</span>
<span class="line" id="L133"></span>
<span class="line" id="L134"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..mcu_width) |mcu_x| {</span>
<span class="line" id="L135"> <span class="tok-kw">const</span> x = mcu_origin_x + mcu_x;</span>
<span class="line" id="L136"> <span class="tok-kw">if</span> (x &gt;= width) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L137"></span>
<span class="line" id="L138"> <span class="tok-comment">// x coordinates in the block</span>
</span>
<span class="line" id="L139"> <span class="tok-kw">const</span> block_x = mcu_x % <span class="tok-number">8</span>;</span>
<span class="line" id="L140"></span>
<span class="line" id="L141"> <span class="tok-kw">const</span> reconstructed_Y = idct(mcu_storage, <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(block_x)), <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(block_y)), mcu_id, <span class="tok-number">0</span>);</span>
<span class="line" id="L142"> <span class="tok-kw">const</span> Y: <span class="tok-type">f32</span> = <span class="tok-builtin">@floatFromInt</span>(reconstructed_Y);</span>
<span class="line" id="L143"> pixels[stride + x] = .{</span>
<span class="line" id="L144"> .value = <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intFromFloat</span>(std.math.clamp(Y + <span class="tok-number">128.0</span>, <span class="tok-number">0.0</span>, <span class="tok-number">255.0</span>))),</span>
<span class="line" id="L145"> };</span>
<span class="line" id="L146"> }</span>
<span class="line" id="L147"> }</span>
<span class="line" id="L148">}</span>
<span class="line" id="L149"></span>
<span class="line" id="L150"><span class="tok-kw">fn</span> <span class="tok-fn">renderToPixelsRgb</span>(self: *<span class="tok-kw">const</span> Self, mcu_storage: *[MAX_COMPONENTS][MAX_BLOCKS]MCU, mcu_id: <span class="tok-type">usize</span>, pixels: []color.Rgb24) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L151"> <span class="tok-kw">const</span> max_horizontal_sampling_factor = self.frame_header.getMaxHorizontalSamplingFactor();</span>
<span class="line" id="L152"> <span class="tok-kw">const</span> max_vertical_sampling_factor = self.frame_header.getMaxVerticalSamplingFactor();</span>
<span class="line" id="L153"> <span class="tok-kw">const</span> mcu_width = <span class="tok-number">8</span> * max_horizontal_sampling_factor;</span>
<span class="line" id="L154"> <span class="tok-kw">const</span> mcu_height = <span class="tok-number">8</span> * max_vertical_sampling_factor;</span>
<span class="line" id="L155"> <span class="tok-kw">const</span> width = self.frame_header.samples_per_row;</span>
<span class="line" id="L156"> <span class="tok-kw">const</span> height = pixels.len / width;</span>
<span class="line" id="L157"> <span class="tok-kw">const</span> mcus_per_row = (width + mcu_width - <span class="tok-number">1</span>) / mcu_width;</span>
<span class="line" id="L158"></span>
<span class="line" id="L159"> <span class="tok-kw">const</span> mcu_origin_x = (mcu_id % mcus_per_row) * mcu_width;</span>
<span class="line" id="L160"> <span class="tok-kw">const</span> mcu_origin_y = (mcu_id / mcus_per_row) * mcu_height;</span>
<span class="line" id="L161"></span>
<span class="line" id="L162"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..mcu_height) |mcu_y| {</span>
<span class="line" id="L163"> <span class="tok-kw">const</span> y = mcu_origin_y + mcu_y;</span>
<span class="line" id="L164"> <span class="tok-kw">if</span> (y &gt;= height) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L165"></span>
<span class="line" id="L166"> <span class="tok-comment">// y coordinates of each component applied to the sampling factor</span>
</span>
<span class="line" id="L167"> <span class="tok-kw">const</span> y_sampled_y = (mcu_y * self.frame_header.components[<span class="tok-number">0</span>].vertical_sampling_factor) / max_vertical_sampling_factor;</span>
<span class="line" id="L168"> <span class="tok-kw">const</span> cb_sampled_y = (mcu_y * self.frame_header.components[<span class="tok-number">1</span>].vertical_sampling_factor) / max_vertical_sampling_factor;</span>
<span class="line" id="L169"> <span class="tok-kw">const</span> cr_sampled_y = (mcu_y * self.frame_header.components[<span class="tok-number">2</span>].vertical_sampling_factor) / max_vertical_sampling_factor;</span>
<span class="line" id="L170"></span>
<span class="line" id="L171"> <span class="tok-comment">// y coordinates of each component in the block</span>
</span>
<span class="line" id="L172"> <span class="tok-kw">const</span> y_block_y = y_sampled_y % <span class="tok-number">8</span>;</span>
<span class="line" id="L173"> <span class="tok-kw">const</span> cb_block_y = cb_sampled_y % <span class="tok-number">8</span>;</span>
<span class="line" id="L174"> <span class="tok-kw">const</span> cr_block_y = cr_sampled_y % <span class="tok-number">8</span>;</span>
<span class="line" id="L175"></span>
<span class="line" id="L176"> <span class="tok-kw">const</span> stride = y * width;</span>
<span class="line" id="L177"></span>
<span class="line" id="L178"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..mcu_width) |mcu_x| {</span>
<span class="line" id="L179"> <span class="tok-kw">const</span> x = mcu_origin_x + mcu_x;</span>
<span class="line" id="L180"> <span class="tok-kw">if</span> (x &gt;= width) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L181"></span>
<span class="line" id="L182"> <span class="tok-comment">// x coordinates of each component applied to the sampling factor</span>
</span>
<span class="line" id="L183"> <span class="tok-kw">const</span> y_sampled_x = (mcu_x * self.frame_header.components[<span class="tok-number">0</span>].horizontal_sampling_factor) / max_horizontal_sampling_factor;</span>
<span class="line" id="L184"> <span class="tok-kw">const</span> cb_sampled_x = (mcu_x * self.frame_header.components[<span class="tok-number">1</span>].horizontal_sampling_factor) / max_horizontal_sampling_factor;</span>
<span class="line" id="L185"> <span class="tok-kw">const</span> cr_sampled_x = (mcu_x * self.frame_header.components[<span class="tok-number">2</span>].horizontal_sampling_factor) / max_horizontal_sampling_factor;</span>
<span class="line" id="L186"></span>
<span class="line" id="L187"> <span class="tok-comment">// x coordinates of each component in the block</span>
</span>
<span class="line" id="L188"> <span class="tok-kw">const</span> y_block_x = y_sampled_x % <span class="tok-number">8</span>;</span>
<span class="line" id="L189"> <span class="tok-kw">const</span> cb_block_x = cb_sampled_x % <span class="tok-number">8</span>;</span>
<span class="line" id="L190"> <span class="tok-kw">const</span> cr_block_x = cr_sampled_x % <span class="tok-number">8</span>;</span>
<span class="line" id="L191"></span>
<span class="line" id="L192"> <span class="tok-kw">const</span> y_block_ind = (y_sampled_y / <span class="tok-number">8</span>) * self.frame_header.components[<span class="tok-number">0</span>].horizontal_sampling_factor + (y_sampled_x / <span class="tok-number">8</span>);</span>
<span class="line" id="L193"> <span class="tok-kw">const</span> cb_block_ind = (cb_sampled_y / <span class="tok-number">8</span>) * self.frame_header.components[<span class="tok-number">1</span>].horizontal_sampling_factor + (cb_sampled_x / <span class="tok-number">8</span>);</span>
<span class="line" id="L194"> <span class="tok-kw">const</span> cr_block_ind = (cr_sampled_y / <span class="tok-number">8</span>) * self.frame_header.components[<span class="tok-number">2</span>].horizontal_sampling_factor + (cr_sampled_x / <span class="tok-number">8</span>);</span>
<span class="line" id="L195"></span>
<span class="line" id="L196"> <span class="tok-kw">const</span> mcu_Y = &amp;mcu_storage[<span class="tok-number">0</span>][y_block_ind];</span>
<span class="line" id="L197"> <span class="tok-kw">const</span> mcu_Cb = &amp;mcu_storage[<span class="tok-number">1</span>][cb_block_ind];</span>
<span class="line" id="L198"> <span class="tok-kw">const</span> mcu_Cr = &amp;mcu_storage[<span class="tok-number">2</span>][cr_block_ind];</span>
<span class="line" id="L199"></span>
<span class="line" id="L200"> <span class="tok-kw">const</span> reconstructed_Y = idct(mcu_Y, <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(y_block_x)), <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(y_block_y)), mcu_id, <span class="tok-number">0</span>);</span>
<span class="line" id="L201"> <span class="tok-kw">const</span> reconstructed_Cb = idct(mcu_Cb, <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(cb_block_x)), <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(cb_block_y)), mcu_id, <span class="tok-number">1</span>);</span>
<span class="line" id="L202"> <span class="tok-kw">const</span> reconstructed_Cr = idct(mcu_Cr, <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(cr_block_x)), <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(cr_block_y)), mcu_id, <span class="tok-number">2</span>);</span>
<span class="line" id="L203"></span>
<span class="line" id="L204"> <span class="tok-kw">const</span> Y: <span class="tok-type">f32</span> = <span class="tok-builtin">@floatFromInt</span>(reconstructed_Y);</span>
<span class="line" id="L205"> <span class="tok-kw">const</span> Cb: <span class="tok-type">f32</span> = <span class="tok-builtin">@floatFromInt</span>(reconstructed_Cb);</span>
<span class="line" id="L206"> <span class="tok-kw">const</span> Cr: <span class="tok-type">f32</span> = <span class="tok-builtin">@floatFromInt</span>(reconstructed_Cr);</span>
<span class="line" id="L207"></span>
<span class="line" id="L208"> <span class="tok-kw">const</span> Co_red = <span class="tok-number">0.299</span>;</span>
<span class="line" id="L209"> <span class="tok-kw">const</span> Co_green = <span class="tok-number">0.587</span>;</span>
<span class="line" id="L210"> <span class="tok-kw">const</span> Co_blue = <span class="tok-number">0.114</span>;</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> <span class="tok-kw">const</span> r = Cr * (<span class="tok-number">2</span> - <span class="tok-number">2</span> * Co_red) + Y;</span>
<span class="line" id="L213"> <span class="tok-kw">const</span> b = Cb * (<span class="tok-number">2</span> - <span class="tok-number">2</span> * Co_blue) + Y;</span>
<span class="line" id="L214"> <span class="tok-kw">const</span> g = (Y - Co_blue * b - Co_red * r) / Co_green;</span>
<span class="line" id="L215"></span>
<span class="line" id="L216"> pixels[stride + x] = .{</span>
<span class="line" id="L217"> .r = <span class="tok-builtin">@intFromFloat</span>(std.math.clamp(r + <span class="tok-number">128.0</span>, <span class="tok-number">0.0</span>, <span class="tok-number">255.0</span>)),</span>
<span class="line" id="L218"> .g = <span class="tok-builtin">@intFromFloat</span>(std.math.clamp(g + <span class="tok-number">128.0</span>, <span class="tok-number">0.0</span>, <span class="tok-number">255.0</span>)),</span>
<span class="line" id="L219"> .b = <span class="tok-builtin">@intFromFloat</span>(std.math.clamp(b + <span class="tok-number">128.0</span>, <span class="tok-number">0.0</span>, <span class="tok-number">255.0</span>)),</span>
<span class="line" id="L220"> };</span>
<span class="line" id="L221"> }</span>
<span class="line" id="L222"> }</span>
<span class="line" id="L223">}</span>
<span class="line" id="L224"></span>
<span class="line" id="L225"><span class="tok-kw">fn</span> <span class="tok-fn">idct</span>(mcu: *<span class="tok-kw">const</span> MCU, x: <span class="tok-type">u3</span>, y: <span class="tok-type">u3</span>, mcu_id: <span class="tok-type">usize</span>, component_id: <span class="tok-type">usize</span>) <span class="tok-type">i8</span> {</span>
<span class="line" id="L226"> <span class="tok-comment">// TODO(angelo): if Ns &gt; 1 it is not interleaved, so the order this should be fixed...</span>
</span>
<span class="line" id="L227"> <span class="tok-comment">// FIXME is wrong for Ns &gt; 1</span>
</span>
<span class="line" id="L228"> <span class="tok-kw">var</span> reconstructed_pixel: <span class="tok-type">f32</span> = <span class="tok-number">0.0</span>;</span>
<span class="line" id="L229"></span>
<span class="line" id="L230"> <span class="tok-kw">var</span> u: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L231"> <span class="tok-kw">while</span> (u &lt; <span class="tok-number">8</span>) : (u += <span class="tok-number">1</span>) {</span>
<span class="line" id="L232"> <span class="tok-kw">var</span> v: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L233"> <span class="tok-kw">while</span> (v &lt; <span class="tok-number">8</span>) : (v += <span class="tok-number">1</span>) {</span>
<span class="line" id="L234"> <span class="tok-kw">const</span> mcu_value = mcu[v * <span class="tok-number">8</span> + u];</span>
<span class="line" id="L235"> reconstructed_pixel += IDCTMultipliers[y][x][u][v] * <span class="tok-builtin">@as</span>(<span class="tok-type">f32</span>, <span class="tok-builtin">@floatFromInt</span>(mcu_value));</span>
<span class="line" id="L236"> }</span>
<span class="line" id="L237"> }</span>
<span class="line" id="L238"></span>
<span class="line" id="L239"> <span class="tok-kw">const</span> scaled_pixel = <span class="tok-builtin">@round</span>(reconstructed_pixel / <span class="tok-number">4.0</span>);</span>
<span class="line" id="L240"> <span class="tok-kw">if</span> (JPEG_DEBUG) {</span>
<span class="line" id="L241"> <span class="tok-kw">if</span> (scaled_pixel &lt; -<span class="tok-number">128.0</span> <span class="tok-kw">or</span> scaled_pixel &gt; <span class="tok-number">127.0</span>) {</span>
<span class="line" id="L242"> std.debug.print(<span class="tok-str">&quot;Pixel at mcu={} x={} y={} component_id={} is out of bounds with DCT: {d}!\n&quot;</span>, .{ mcu_id, x, y, component_id, scaled_pixel });</span>
<span class="line" id="L243"> }</span>
<span class="line" id="L244"> }</span>
<span class="line" id="L245"></span>
<span class="line" id="L246"> <span class="tok-kw">return</span> <span class="tok-builtin">@intFromFloat</span>(std.math.clamp(scaled_pixel, -<span class="tok-number">128.0</span>, <span class="tok-number">127.0</span>));</span>
<span class="line" id="L247">}</span>
<span class="line" id="L248"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,267 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/jpeg/FrameHeader.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! this module implements the frame header followint the t-81 specs,</span></span>
<span class="line" id="L2"><span class="tok-comment">//! section b.2.2 Frame Header Syntax</span></span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../Image.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L9"></span>
<span class="line" id="L10"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-kw">const</span> JPEG_DEBUG = <span class="tok-null">false</span>;</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> Component = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L15"> id: <span class="tok-type">u8</span>,</span>
<span class="line" id="L16"> horizontal_sampling_factor: <span class="tok-type">u4</span>,</span>
<span class="line" id="L17"> vertical_sampling_factor: <span class="tok-type">u4</span>,</span>
<span class="line" id="L18"> quantization_table_id: <span class="tok-type">u8</span>,</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!Component {</span>
<span class="line" id="L21"> <span class="tok-kw">const</span> component_id = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L22"> <span class="tok-kw">const</span> sampling_factors = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L23"> <span class="tok-kw">const</span> quantization_table_id = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"> <span class="tok-kw">const</span> horizontal_sampling_factor: <span class="tok-type">u4</span> = <span class="tok-builtin">@intCast</span>(sampling_factors &gt;&gt; <span class="tok-number">4</span>);</span>
<span class="line" id="L26"> <span class="tok-kw">const</span> vertical_sampling_factor: <span class="tok-type">u4</span> = <span class="tok-builtin">@intCast</span>(sampling_factors &amp; <span class="tok-number">0xF</span>);</span>
<span class="line" id="L27"></span>
<span class="line" id="L28"> <span class="tok-kw">if</span> (horizontal_sampling_factor &lt; <span class="tok-number">1</span> <span class="tok-kw">or</span> horizontal_sampling_factor &gt; <span class="tok-number">4</span>) {</span>
<span class="line" id="L29"> <span class="tok-comment">// TODO(angelo): error, create cusotm error</span>
</span>
<span class="line" id="L30"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L31"> }</span>
<span class="line" id="L32"></span>
<span class="line" id="L33"> <span class="tok-kw">if</span> (vertical_sampling_factor &lt; <span class="tok-number">1</span> <span class="tok-kw">or</span> vertical_sampling_factor &gt; <span class="tok-number">4</span>) {</span>
<span class="line" id="L34"> <span class="tok-comment">// TODO(angelo): error, create custom error</span>
</span>
<span class="line" id="L35"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L36"> }</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"> <span class="tok-kw">if</span> (quantization_table_id &gt; <span class="tok-number">3</span>) {</span>
<span class="line" id="L39"> <span class="tok-comment">// TODO(angelo): error, create custom error</span>
</span>
<span class="line" id="L40"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L41"> }</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"> <span class="tok-kw">return</span> Component{</span>
<span class="line" id="L44"> .id = component_id,</span>
<span class="line" id="L45"> .horizontal_sampling_factor = horizontal_sampling_factor,</span>
<span class="line" id="L46"> .vertical_sampling_factor = vertical_sampling_factor,</span>
<span class="line" id="L47"> .quantization_table_id = quantization_table_id,</span>
<span class="line" id="L48"> };</span>
<span class="line" id="L49"> }</span>
<span class="line" id="L50">};</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"><span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L53"></span>
<span class="line" id="L54">allocator: Allocator,</span>
<span class="line" id="L55">sample_precision: <span class="tok-type">u8</span>,</span>
<span class="line" id="L56">row_count: <span class="tok-type">u16</span>,</span>
<span class="line" id="L57">samples_per_row: <span class="tok-type">u16</span>,</span>
<span class="line" id="L58">components: []Component,</span>
<span class="line" id="L59"></span>
<span class="line" id="L60"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(allocator: Allocator, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!Self {</span>
<span class="line" id="L61"> <span class="tok-kw">const</span> segment_size = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L62"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;StartOfFrame: frame size = 0x{X}\n&quot;</span>, .{segment_size});</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"> <span class="tok-kw">const</span> sample_precision = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L65"> <span class="tok-kw">const</span> row_count = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L66"> <span class="tok-kw">const</span> samples_per_row = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"> <span class="tok-kw">const</span> component_count = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-kw">if</span> (component_count != <span class="tok-number">1</span> <span class="tok-kw">and</span> component_count != <span class="tok-number">3</span>) {</span>
<span class="line" id="L71"> <span class="tok-comment">// TODO(angelo): use jpeg error here, for components</span>
</span>
<span class="line" id="L72"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot; {}x{}, precision={}, {} components\n&quot;</span>, .{ samples_per_row, row_count, sample_precision, component_count });</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"> <span class="tok-kw">var</span> components = <span class="tok-kw">try</span> allocator.alloc(Component, component_count);</span>
<span class="line" id="L78"> <span class="tok-kw">errdefer</span> allocator.free(components);</span>
<span class="line" id="L79"></span>
<span class="line" id="L80"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L81"> <span class="tok-kw">while</span> (i &lt; component_count) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L82"> components[i] = <span class="tok-kw">try</span> Component.read(reader);</span>
<span class="line" id="L83"> <span class="tok-comment">// TODO(angelo): remove this</span>
</span>
<span class="line" id="L84"> <span class="tok-comment">// if (JPEG_VERY_DEBUG) {</span>
</span>
<span class="line" id="L85"> <span class="tok-comment">// std.debug.print(&quot; ID={}, Vfactor={}, Hfactor={} QtableID={}\n&quot;, .{</span>
</span>
<span class="line" id="L86"> <span class="tok-comment">// components[i].id, components[i].vertical_sampling_factor, components[i].horizontal_sampling_factor, components[i].quantization_table_id,</span>
</span>
<span class="line" id="L87"> <span class="tok-comment">// });</span>
</span>
<span class="line" id="L88"> <span class="tok-comment">// }</span>
</span>
<span class="line" id="L89"> }</span>
<span class="line" id="L90"></span>
<span class="line" id="L91"> <span class="tok-comment">// see B 8.2 table for the meaning of this check.</span>
</span>
<span class="line" id="L92"> std.debug.assert(segment_size == <span class="tok-number">8</span> + <span class="tok-number">3</span> * component_count);</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"> <span class="tok-kw">return</span> Self{</span>
<span class="line" id="L95"> .allocator = allocator,</span>
<span class="line" id="L96"> .sample_precision = sample_precision,</span>
<span class="line" id="L97"> .row_count = row_count,</span>
<span class="line" id="L98"> .samples_per_row = samples_per_row,</span>
<span class="line" id="L99"> .components = components,</span>
<span class="line" id="L100"> };</span>
<span class="line" id="L101">}</span>
<span class="line" id="L102"></span>
<span class="line" id="L103"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L104"> self.allocator.free(self.components);</span>
<span class="line" id="L105">}</span>
<span class="line" id="L106"></span>
<span class="line" id="L107"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getMaxHorizontalSamplingFactor</span>(self: Self) <span class="tok-type">usize</span> {</span>
<span class="line" id="L108"> <span class="tok-kw">var</span> ret: <span class="tok-type">u4</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L109"> <span class="tok-kw">for</span> (self.components) |component| {</span>
<span class="line" id="L110"> <span class="tok-kw">if</span> (ret &lt; component.horizontal_sampling_factor) {</span>
<span class="line" id="L111"> ret = component.horizontal_sampling_factor;</span>
<span class="line" id="L112"> }</span>
<span class="line" id="L113"> }</span>
<span class="line" id="L114"></span>
<span class="line" id="L115"> <span class="tok-kw">return</span> ret;</span>
<span class="line" id="L116">}</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getMaxVerticalSamplingFactor</span>(self: Self) <span class="tok-type">usize</span> {</span>
<span class="line" id="L119"> <span class="tok-kw">var</span> ret: <span class="tok-type">u4</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L120"> <span class="tok-kw">for</span> (self.components) |component| {</span>
<span class="line" id="L121"> <span class="tok-kw">if</span> (ret &lt; component.vertical_sampling_factor) {</span>
<span class="line" id="L122"> ret = component.vertical_sampling_factor;</span>
<span class="line" id="L123"> }</span>
<span class="line" id="L124"> }</span>
<span class="line" id="L125"></span>
<span class="line" id="L126"> <span class="tok-kw">return</span> ret;</span>
<span class="line" id="L127">}</span>
<span class="line" id="L128"></span>
<span class="line" id="L129"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getBlockCount</span>(self: Self, component_id: <span class="tok-type">usize</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L130"> <span class="tok-comment">// MCU of non-interleaved is just one block.</span>
</span>
<span class="line" id="L131"> <span class="tok-kw">if</span> (self.components.len == <span class="tok-number">1</span>) {</span>
<span class="line" id="L132"> <span class="tok-kw">return</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L133"> }</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"> <span class="tok-kw">const</span> horizontal_block_count = self.components[component_id].horizontal_sampling_factor;</span>
<span class="line" id="L136"> <span class="tok-kw">const</span> vertical_block_count = self.components[component_id].vertical_sampling_factor;</span>
<span class="line" id="L137"> <span class="tok-kw">return</span> horizontal_block_count * vertical_block_count;</span>
<span class="line" id="L138">}</span>
<span class="line" id="L139"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,202 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/jpeg/JFIFHeader.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! this module implements the JFIF header</span></span>
<span class="line" id="L2"><span class="tok-comment">//! specified in https://www.w3.org/Graphics/JPEG/itu-t81.pdf</span></span>
<span class="line" id="L3"><span class="tok-comment">//! section B.2.1 and assumes that there will be an application0 segment.</span></span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../Image.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">const</span> Markers = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./utils.zig&quot;</span>).Markers;</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-comment">/// see https://www.ecma-international.org/wp-content/uploads/ECMA_TR-98_1st_edition_june_2009.pdf</span></span>
<span class="line" id="L14"><span class="tok-comment">/// chapt 10.</span></span>
<span class="line" id="L15"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> DensityUnit = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L16"> pixels = <span class="tok-number">0</span>,</span>
<span class="line" id="L17"> dots_per_inch = <span class="tok-number">1</span>,</span>
<span class="line" id="L18"> dots_per_cm = <span class="tok-number">2</span>,</span>
<span class="line" id="L19">};</span>
<span class="line" id="L20"></span>
<span class="line" id="L21">jfif_revision: <span class="tok-type">u16</span>,</span>
<span class="line" id="L22">density_unit: DensityUnit,</span>
<span class="line" id="L23">x_density: <span class="tok-type">u16</span>,</span>
<span class="line" id="L24">y_density: <span class="tok-type">u16</span>,</span>
<span class="line" id="L25"></span>
<span class="line" id="L26"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(buffered_stream: *buffered_stream_source.DefaultBufferedStreamSourceReader) !Self {</span>
<span class="line" id="L27"> <span class="tok-comment">// Read the first APP0 header.</span>
</span>
<span class="line" id="L28"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L29"> <span class="tok-kw">try</span> buffered_stream.seekTo(<span class="tok-number">2</span>);</span>
<span class="line" id="L30"> <span class="tok-kw">const</span> maybe_app0_marker = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L31"> <span class="tok-kw">if</span> (maybe_app0_marker != <span class="tok-builtin">@intFromEnum</span>(Markers.application0)) {</span>
<span class="line" id="L32"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.App0MarkerDoesNotExist;</span>
<span class="line" id="L33"> }</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"> <span class="tok-comment">// Header length</span>
</span>
<span class="line" id="L36"> _ = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"> <span class="tok-kw">var</span> identifier_buffer: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L39"> _ = <span class="tok-kw">try</span> reader.read(identifier_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L40"></span>
<span class="line" id="L41"> <span class="tok-kw">if</span> (!std.mem.eql(<span class="tok-type">u8</span>, identifier_buffer[<span class="tok-number">0</span>..], <span class="tok-str">&quot;JFIF&quot;</span>)) {</span>
<span class="line" id="L42"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.JfifIdentifierNotSet;</span>
<span class="line" id="L43"> }</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"> <span class="tok-comment">// NUL byte after JFIF</span>
</span>
<span class="line" id="L46"> _ = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L47"></span>
<span class="line" id="L48"> <span class="tok-kw">const</span> jfif_revision = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L49"> <span class="tok-kw">const</span> density_unit: DensityUnit = <span class="tok-builtin">@enumFromInt</span>(<span class="tok-kw">try</span> reader.readByte());</span>
<span class="line" id="L50"> <span class="tok-kw">const</span> x_density = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L51"> <span class="tok-kw">const</span> y_density = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L52"></span>
<span class="line" id="L53"> <span class="tok-kw">const</span> thumbnailWidth = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L54"> <span class="tok-kw">const</span> thumbnailHeight = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L55"></span>
<span class="line" id="L56"> <span class="tok-kw">if</span> (thumbnailWidth != <span class="tok-number">0</span> <span class="tok-kw">or</span> thumbnailHeight != <span class="tok-number">0</span>) {</span>
<span class="line" id="L57"> <span class="tok-comment">// TODO: Support thumbnails (not important)</span>
</span>
<span class="line" id="L58"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.ThumbnailImagesUnsupported;</span>
<span class="line" id="L59"> }</span>
<span class="line" id="L60"></span>
<span class="line" id="L61"> <span class="tok-comment">// Make sure there are no application markers after us.</span>
</span>
<span class="line" id="L62"> <span class="tok-comment">// TODO: Support application markers, present in versions 1.02 and above.</span>
</span>
<span class="line" id="L63"> <span class="tok-comment">// see https://www.ecma-international.org/wp-content/uploads/ECMA_TR-98_1st_edition_june_2009.pdf</span>
</span>
<span class="line" id="L64"> <span class="tok-comment">// chapt 10.1</span>
</span>
<span class="line" id="L65"> <span class="tok-kw">if</span> (((<span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big)) &amp; <span class="tok-number">0xFFF0</span>) == <span class="tok-builtin">@intFromEnum</span>(Markers.application0)) {</span>
<span class="line" id="L66"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.ExtraneousApplicationMarker;</span>
<span class="line" id="L67"> }</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"> <span class="tok-kw">try</span> buffered_stream.seekBy(-<span class="tok-number">2</span>);</span>
<span class="line" id="L70"></span>
<span class="line" id="L71"> <span class="tok-kw">return</span> Self{</span>
<span class="line" id="L72"> .jfif_revision = jfif_revision,</span>
<span class="line" id="L73"> .density_unit = density_unit,</span>
<span class="line" id="L74"> .x_density = x_density,</span>
<span class="line" id="L75"> .y_density = y_density,</span>
<span class="line" id="L76"> };</span>
<span class="line" id="L77">}</span>
<span class="line" id="L78"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,393 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/jpeg/Scan.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../color.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../Image.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">const</span> FrameHeader = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;FrameHeader.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">const</span> Frame = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;Frame.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> HuffmanReader = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;huffman.zig&quot;</span>).Reader;</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-kw">const</span> MAX_COMPONENTS = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).MAX_COMPONENTS;</span>
<span class="line" id="L13"><span class="tok-kw">const</span> MAX_BLOCKS = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).MAX_BLOCKS;</span>
<span class="line" id="L14"><span class="tok-kw">const</span> MCU = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).MCU;</span>
<span class="line" id="L15"><span class="tok-kw">const</span> ZigzagOffsets = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;utils.zig&quot;</span>).ZigzagOffsets;</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"><span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"><span class="tok-kw">const</span> JPEG_DEBUG = <span class="tok-null">false</span>;</span>
<span class="line" id="L20"><span class="tok-kw">const</span> JPEG_VERY_DEBUG = <span class="tok-null">false</span>;</span>
<span class="line" id="L21"></span>
<span class="line" id="L22">frame: *<span class="tok-kw">const</span> Frame,</span>
<span class="line" id="L23">reader: HuffmanReader,</span>
<span class="line" id="L24">scan_header: ScanHeader,</span>
<span class="line" id="L25">mcu_storage: [MAX_COMPONENTS][MAX_BLOCKS]MCU,</span>
<span class="line" id="L26">prediction_values: [<span class="tok-number">3</span>]<span class="tok-type">i12</span>,</span>
<span class="line" id="L27"></span>
<span class="line" id="L28"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(frame: *<span class="tok-kw">const</span> Frame, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!Self {</span>
<span class="line" id="L29"> <span class="tok-kw">const</span> scan_header = <span class="tok-kw">try</span> ScanHeader.read(reader);</span>
<span class="line" id="L30"> <span class="tok-kw">return</span> Self{</span>
<span class="line" id="L31"> .frame = frame,</span>
<span class="line" id="L32"> .reader = HuffmanReader.init(reader),</span>
<span class="line" id="L33"> .scan_header = scan_header,</span>
<span class="line" id="L34"> .mcu_storage = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L35"> .prediction_values = [<span class="tok-number">3</span>]<span class="tok-type">i12</span>{ <span class="tok-number">0</span>, <span class="tok-number">0</span>, <span class="tok-number">0</span> },</span>
<span class="line" id="L36"> };</span>
<span class="line" id="L37">}</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"><span class="tok-comment">/// Perform the scan operation.</span></span>
<span class="line" id="L40"><span class="tok-comment">/// We assume the AC and DC huffman tables are already set up, and ready to decode.</span></span>
<span class="line" id="L41"><span class="tok-comment">/// This should implement section E.2.3 of t-81 1992.</span></span>
<span class="line" id="L42"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">performScan</span>(frame: *<span class="tok-kw">const</span> Frame, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader, pixels_opt: *?color.PixelStorage) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L43"> <span class="tok-kw">var</span> self = <span class="tok-kw">try</span> Self.init(frame, reader);</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"> <span class="tok-kw">const</span> mcu_count = Self.calculateMCUCountInFrame(&amp;frame.frame_header);</span>
<span class="line" id="L46"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..mcu_count) |mcu_id| {</span>
<span class="line" id="L47"> <span class="tok-kw">try</span> self.decodeMCU();</span>
<span class="line" id="L48"> <span class="tok-kw">try</span> self.dequantize();</span>
<span class="line" id="L49"> <span class="tok-kw">try</span> frame.renderToPixels(&amp;self.mcu_storage, mcu_id, &amp;pixels_opt.*.?);</span>
<span class="line" id="L50"> }</span>
<span class="line" id="L51">}</span>
<span class="line" id="L52"></span>
<span class="line" id="L53"><span class="tok-kw">fn</span> <span class="tok-fn">dequantize</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L54"> <span class="tok-kw">for</span> (self.frame.frame_header.components, <span class="tok-number">0</span>..) |component, component_id| {</span>
<span class="line" id="L55"> <span class="tok-kw">const</span> block_count = self.frame.frame_header.getBlockCount(component_id);</span>
<span class="line" id="L56"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..block_count) |i| {</span>
<span class="line" id="L57"> <span class="tok-kw">const</span> block = &amp;self.mcu_storage[component_id][i];</span>
<span class="line" id="L58"></span>
<span class="line" id="L59"> <span class="tok-kw">if</span> (self.frame.quantization_tables[component.quantization_table_id]) |quantization_table| {</span>
<span class="line" id="L60"> <span class="tok-kw">var</span> sample_id: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L61"> <span class="tok-kw">while</span> (sample_id &lt; <span class="tok-number">64</span>) : (sample_id += <span class="tok-number">1</span>) {</span>
<span class="line" id="L62"> block[sample_id] = block[sample_id] * quantization_table.q8[sample_id];</span>
<span class="line" id="L63"> }</span>
<span class="line" id="L64"> } <span class="tok-kw">else</span> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L65"> }</span>
<span class="line" id="L66"> }</span>
<span class="line" id="L67">}</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"><span class="tok-kw">fn</span> <span class="tok-fn">calculateMCUCountInFrame</span>(frame_header: *<span class="tok-kw">const</span> FrameHeader) <span class="tok-type">usize</span> {</span>
<span class="line" id="L70"> <span class="tok-comment">// FIXME: This is very naive and probably only works for Baseline DCT.</span>
</span>
<span class="line" id="L71"> <span class="tok-comment">// MCU of non-interleaved is just one block.</span>
</span>
<span class="line" id="L72"> <span class="tok-kw">const</span> horizontal_block_count = <span class="tok-kw">if</span> (<span class="tok-number">1</span> &lt; frame_header.components.len) frame_header.getMaxHorizontalSamplingFactor() <span class="tok-kw">else</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L73"> <span class="tok-kw">const</span> vertical_block_count = <span class="tok-kw">if</span> (<span class="tok-number">1</span> &lt; frame_header.components.len) frame_header.getMaxVerticalSamplingFactor() <span class="tok-kw">else</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L74"> <span class="tok-kw">const</span> mcu_width = <span class="tok-number">8</span> * horizontal_block_count;</span>
<span class="line" id="L75"> <span class="tok-kw">const</span> mcu_height = <span class="tok-number">8</span> * vertical_block_count;</span>
<span class="line" id="L76"> <span class="tok-kw">const</span> mcu_count_per_row = (frame_header.samples_per_row + mcu_width - <span class="tok-number">1</span>) / mcu_width;</span>
<span class="line" id="L77"> <span class="tok-kw">const</span> mcu_count_per_column = (frame_header.row_count + mcu_height - <span class="tok-number">1</span>) / mcu_height;</span>
<span class="line" id="L78"> <span class="tok-kw">return</span> mcu_count_per_row * mcu_count_per_column;</span>
<span class="line" id="L79">}</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"><span class="tok-kw">fn</span> <span class="tok-fn">decodeMCU</span>(self: *Self) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L82"> <span class="tok-kw">for</span> (self.scan_header.components, <span class="tok-number">0</span>..) |maybe_component, component_id| {</span>
<span class="line" id="L83"> _ = component_id;</span>
<span class="line" id="L84"> <span class="tok-kw">if</span> (maybe_component == <span class="tok-null">null</span>)</span>
<span class="line" id="L85"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-kw">try</span> self.decodeMCUComponent(maybe_component.?);</span>
<span class="line" id="L88"> }</span>
<span class="line" id="L89">}</span>
<span class="line" id="L90"></span>
<span class="line" id="L91"><span class="tok-kw">fn</span> <span class="tok-fn">decodeMCUComponent</span>(self: *Self, component: ScanComponentSpec) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L92"> <span class="tok-comment">// The encoder might reorder components or omit one if it decides that the</span>
</span>
<span class="line" id="L93"> <span class="tok-comment">// file size can be reduced that way. Therefore we need to select the correct</span>
</span>
<span class="line" id="L94"> <span class="tok-comment">// destination for this component.</span>
</span>
<span class="line" id="L95"> <span class="tok-kw">const</span> component_destination: <span class="tok-type">usize</span> = blk: {</span>
<span class="line" id="L96"> <span class="tok-kw">for</span> (self.frame.frame_header.components, <span class="tok-number">0</span>..) |frame_component, i| {</span>
<span class="line" id="L97"> <span class="tok-kw">if</span> (frame_component.id == component.component_selector) {</span>
<span class="line" id="L98"> <span class="tok-kw">break</span> :blk i;</span>
<span class="line" id="L99"> }</span>
<span class="line" id="L100"> }</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L103"> };</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"> <span class="tok-kw">const</span> block_count = self.frame.frame_header.getBlockCount(component_destination);</span>
<span class="line" id="L106"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..block_count) |i| {</span>
<span class="line" id="L107"> <span class="tok-kw">const</span> mcu = &amp;self.mcu_storage[component_destination][i];</span>
<span class="line" id="L108"></span>
<span class="line" id="L109"> <span class="tok-comment">// Decode the DC coefficient</span>
</span>
<span class="line" id="L110"> <span class="tok-kw">if</span> (self.frame.dc_huffman_tables[component.dc_table_selector] == <span class="tok-null">null</span>) <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L111"></span>
<span class="line" id="L112"> self.reader.setHuffmanTable(&amp;self.frame.dc_huffman_tables[component.dc_table_selector].?);</span>
<span class="line" id="L113"></span>
<span class="line" id="L114"> <span class="tok-kw">const</span> dc_coefficient = <span class="tok-kw">try</span> self.decodeDCCoefficient(component_destination);</span>
<span class="line" id="L115"> mcu[<span class="tok-number">0</span>] = dc_coefficient;</span>
<span class="line" id="L116"></span>
<span class="line" id="L117"> <span class="tok-comment">// Decode the AC coefficients</span>
</span>
<span class="line" id="L118"> <span class="tok-kw">if</span> (self.frame.ac_huffman_tables[component.ac_table_selector] == <span class="tok-null">null</span>)</span>
<span class="line" id="L119"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L120"></span>
<span class="line" id="L121"> self.reader.setHuffmanTable(&amp;self.frame.ac_huffman_tables[component.ac_table_selector].?);</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"> <span class="tok-kw">try</span> self.decodeACCoefficients(mcu);</span>
<span class="line" id="L124"> }</span>
<span class="line" id="L125">}</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"><span class="tok-kw">fn</span> <span class="tok-fn">decodeDCCoefficient</span>(self: *Self, component_destination: <span class="tok-type">usize</span>) ImageReadError!<span class="tok-type">i12</span> {</span>
<span class="line" id="L128"> <span class="tok-kw">const</span> maybe_magnitude = <span class="tok-kw">try</span> self.reader.readCode();</span>
<span class="line" id="L129"> <span class="tok-kw">if</span> (maybe_magnitude &gt; <span class="tok-number">11</span>) <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L130"> <span class="tok-kw">const</span> magnitude: <span class="tok-type">u4</span> = <span class="tok-builtin">@intCast</span>(maybe_magnitude);</span>
<span class="line" id="L131"></span>
<span class="line" id="L132"> <span class="tok-kw">const</span> diff: <span class="tok-type">i12</span> = <span class="tok-builtin">@intCast</span>(<span class="tok-kw">try</span> self.reader.readMagnitudeCoded(magnitude));</span>
<span class="line" id="L133"> <span class="tok-comment">// TODO: check correctess after refactor</span>
</span>
<span class="line" id="L134"> <span class="tok-kw">const</span> dc_coefficient = diff + self.prediction_values[component_destination];</span>
<span class="line" id="L135"> self.prediction_values[component_destination] = dc_coefficient;</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"> <span class="tok-kw">return</span> dc_coefficient;</span>
<span class="line" id="L138">}</span>
<span class="line" id="L139"></span>
<span class="line" id="L140"><span class="tok-kw">fn</span> <span class="tok-fn">decodeACCoefficients</span>(self: *Self, mcu: *MCU) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L141"> <span class="tok-kw">var</span> ac: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L142"> <span class="tok-kw">var</span> did_see_eob = <span class="tok-null">false</span>;</span>
<span class="line" id="L143"> <span class="tok-kw">while</span> (ac &lt; <span class="tok-number">64</span>) : (ac += <span class="tok-number">1</span>) {</span>
<span class="line" id="L144"> <span class="tok-kw">if</span> (did_see_eob) {</span>
<span class="line" id="L145"> mcu[ZigzagOffsets[ac]] = <span class="tok-number">0</span>;</span>
<span class="line" id="L146"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L147"> }</span>
<span class="line" id="L148"></span>
<span class="line" id="L149"> <span class="tok-kw">const</span> zero_run_length_and_magnitude = <span class="tok-kw">try</span> self.reader.readCode();</span>
<span class="line" id="L150"> <span class="tok-comment">// 00 == EOB</span>
</span>
<span class="line" id="L151"> <span class="tok-kw">if</span> (zero_run_length_and_magnitude == <span class="tok-number">0x00</span>) {</span>
<span class="line" id="L152"> did_see_eob = <span class="tok-null">true</span>;</span>
<span class="line" id="L153"> mcu[ZigzagOffsets[ac]] = <span class="tok-number">0</span>;</span>
<span class="line" id="L154"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L155"> }</span>
<span class="line" id="L156"></span>
<span class="line" id="L157"> <span class="tok-kw">const</span> zero_run_length = zero_run_length_and_magnitude &gt;&gt; <span class="tok-number">4</span>;</span>
<span class="line" id="L158"></span>
<span class="line" id="L159"> <span class="tok-kw">const</span> maybe_magnitude = zero_run_length_and_magnitude &amp; <span class="tok-number">0xF</span>;</span>
<span class="line" id="L160"> <span class="tok-kw">if</span> (maybe_magnitude &gt; <span class="tok-number">10</span>) <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L161"> <span class="tok-kw">const</span> magnitude: <span class="tok-type">u4</span> = <span class="tok-builtin">@intCast</span>(maybe_magnitude);</span>
<span class="line" id="L162"></span>
<span class="line" id="L163"> <span class="tok-kw">const</span> ac_coefficient: <span class="tok-type">i11</span> = <span class="tok-builtin">@intCast</span>(<span class="tok-kw">try</span> self.reader.readMagnitudeCoded(magnitude));</span>
<span class="line" id="L164"></span>
<span class="line" id="L165"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L166"> <span class="tok-kw">while</span> (i &lt; zero_run_length) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L167"> mcu[ZigzagOffsets[ac]] = <span class="tok-number">0</span>;</span>
<span class="line" id="L168"> ac += <span class="tok-number">1</span>;</span>
<span class="line" id="L169"> }</span>
<span class="line" id="L170"></span>
<span class="line" id="L171"> mcu[ZigzagOffsets[ac]] = ac_coefficient;</span>
<span class="line" id="L172"> }</span>
<span class="line" id="L173">}</span>
<span class="line" id="L174"></span>
<span class="line" id="L175"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ScanComponentSpec = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L176"> component_selector: <span class="tok-type">u8</span>,</span>
<span class="line" id="L177"> dc_table_selector: <span class="tok-type">u4</span>,</span>
<span class="line" id="L178"> ac_table_selector: <span class="tok-type">u4</span>,</span>
<span class="line" id="L179"></span>
<span class="line" id="L180"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!ScanComponentSpec {</span>
<span class="line" id="L181"> <span class="tok-kw">const</span> component_selector = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L182"> <span class="tok-kw">const</span> entropy_coding_selectors = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L183"></span>
<span class="line" id="L184"> <span class="tok-kw">const</span> dc_table_selector: <span class="tok-type">u4</span> = <span class="tok-builtin">@intCast</span>(entropy_coding_selectors &gt;&gt; <span class="tok-number">4</span>);</span>
<span class="line" id="L185"> <span class="tok-kw">const</span> ac_table_selector: <span class="tok-type">u4</span> = <span class="tok-builtin">@intCast</span>(entropy_coding_selectors &amp; <span class="tok-number">0b11</span>);</span>
<span class="line" id="L186"></span>
<span class="line" id="L187"> <span class="tok-kw">if</span> (JPEG_VERY_DEBUG) {</span>
<span class="line" id="L188"> std.debug.print(<span class="tok-str">&quot; Component spec: selector={}, DC table ID={}, AC table ID={}\n&quot;</span>, .{ component_selector, dc_table_selector, ac_table_selector });</span>
<span class="line" id="L189"> }</span>
<span class="line" id="L190"></span>
<span class="line" id="L191"> <span class="tok-kw">return</span> ScanComponentSpec{</span>
<span class="line" id="L192"> .component_selector = component_selector,</span>
<span class="line" id="L193"> .dc_table_selector = dc_table_selector,</span>
<span class="line" id="L194"> .ac_table_selector = ac_table_selector,</span>
<span class="line" id="L195"> };</span>
<span class="line" id="L196"> }</span>
<span class="line" id="L197">};</span>
<span class="line" id="L198"></span>
<span class="line" id="L199"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Header = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L200"> components: [<span class="tok-number">4</span>]?ScanComponentSpec,</span>
<span class="line" id="L201"></span>
<span class="line" id="L202"> <span class="tok-comment">/// first DCT coefficient in each block in zig-zag order</span></span>
<span class="line" id="L203"> start_of_spectral_selection: <span class="tok-type">u8</span>,</span>
<span class="line" id="L204"></span>
<span class="line" id="L205"> <span class="tok-comment">/// last DCT coefficient in each block in zig-zag order</span></span>
<span class="line" id="L206"> <span class="tok-comment">/// 63 for sequential DCT, 0 for lossless</span></span>
<span class="line" id="L207"> <span class="tok-comment">/// TODO(angelo) add check for this.</span></span>
<span class="line" id="L208"> end_of_spectral_selection: <span class="tok-type">u8</span>,</span>
<span class="line" id="L209"> approximation_high: <span class="tok-type">u4</span>,</span>
<span class="line" id="L210"> approximation_low: <span class="tok-type">u4</span>,</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!Header {</span>
<span class="line" id="L213"> <span class="tok-kw">const</span> segment_size = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L214"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;StartOfScan: segment size = 0x{X}\n&quot;</span>, .{segment_size});</span>
<span class="line" id="L215"></span>
<span class="line" id="L216"> <span class="tok-kw">const</span> component_count = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L217"> <span class="tok-kw">if</span> (component_count &lt; <span class="tok-number">1</span> <span class="tok-kw">or</span> component_count &gt; <span class="tok-number">4</span>) {</span>
<span class="line" id="L218"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L219"> }</span>
<span class="line" id="L220"></span>
<span class="line" id="L221"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot; Component count: {}\n&quot;</span>, .{component_count});</span>
<span class="line" id="L222"></span>
<span class="line" id="L223"> <span class="tok-kw">var</span> components = [_]?ScanComponentSpec{<span class="tok-null">null</span>} ** <span class="tok-number">4</span>;</span>
<span class="line" id="L224"></span>
<span class="line" id="L225"> <span class="tok-kw">if</span> (JPEG_VERY_DEBUG) std.debug.print(<span class="tok-str">&quot; Components:\n&quot;</span>, .{});</span>
<span class="line" id="L226"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L227"> <span class="tok-kw">while</span> (i &lt; component_count) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L228"> components[i] = <span class="tok-kw">try</span> ScanComponentSpec.read(reader);</span>
<span class="line" id="L229"> }</span>
<span class="line" id="L230"></span>
<span class="line" id="L231"> <span class="tok-kw">const</span> start_of_spectral_selection = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L232"> <span class="tok-kw">const</span> end_of_spectral_selection = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L233"></span>
<span class="line" id="L234"> <span class="tok-kw">if</span> (start_of_spectral_selection &gt; <span class="tok-number">63</span>) {</span>
<span class="line" id="L235"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L236"> }</span>
<span class="line" id="L237"></span>
<span class="line" id="L238"> <span class="tok-kw">if</span> (end_of_spectral_selection &lt; start_of_spectral_selection <span class="tok-kw">or</span> end_of_spectral_selection &gt; <span class="tok-number">63</span>) {</span>
<span class="line" id="L239"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L240"> }</span>
<span class="line" id="L241"></span>
<span class="line" id="L242"> <span class="tok-comment">// If Ss = 0, then Se = 63.</span>
</span>
<span class="line" id="L243"> <span class="tok-kw">if</span> (start_of_spectral_selection == <span class="tok-number">0</span> <span class="tok-kw">and</span> end_of_spectral_selection != <span class="tok-number">63</span>) {</span>
<span class="line" id="L244"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L245"> }</span>
<span class="line" id="L246"></span>
<span class="line" id="L247"> <span class="tok-kw">if</span> (JPEG_VERY_DEBUG) std.debug.print(<span class="tok-str">&quot; Spectral selection: {}-{}\n&quot;</span>, .{ start_of_spectral_selection, end_of_spectral_selection });</span>
<span class="line" id="L248"></span>
<span class="line" id="L249"> <span class="tok-kw">const</span> approximation_bits = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L250"> <span class="tok-kw">const</span> approximation_high: <span class="tok-type">u4</span> = <span class="tok-builtin">@intCast</span>(approximation_bits &gt;&gt; <span class="tok-number">4</span>);</span>
<span class="line" id="L251"> <span class="tok-kw">const</span> approximation_low: <span class="tok-type">u4</span> = <span class="tok-builtin">@intCast</span>(approximation_bits &amp; <span class="tok-number">0b1111</span>);</span>
<span class="line" id="L252"> <span class="tok-kw">if</span> (JPEG_VERY_DEBUG) std.debug.print(<span class="tok-str">&quot; Approximation bit position: high={} low={}\n&quot;</span>, .{ approximation_high, approximation_low });</span>
<span class="line" id="L253"></span>
<span class="line" id="L254"> std.debug.assert(segment_size == <span class="tok-number">2</span> * component_count + <span class="tok-number">1</span> + <span class="tok-number">2</span> + <span class="tok-number">1</span> + <span class="tok-number">2</span>);</span>
<span class="line" id="L255"></span>
<span class="line" id="L256"> <span class="tok-kw">return</span> Header{</span>
<span class="line" id="L257"> .components = components,</span>
<span class="line" id="L258"> .start_of_spectral_selection = start_of_spectral_selection,</span>
<span class="line" id="L259"> .end_of_spectral_selection = end_of_spectral_selection,</span>
<span class="line" id="L260"> .approximation_high = approximation_high,</span>
<span class="line" id="L261"> .approximation_low = approximation_low,</span>
<span class="line" id="L262"> };</span>
<span class="line" id="L263"> }</span>
<span class="line" id="L264">};</span>
<span class="line" id="L265"></span>
<span class="line" id="L266"><span class="tok-kw">const</span> ScanHeader = Header;</span>
<span class="line" id="L267"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,302 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/jpeg/huffman.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! This module contains implementation of huffman table encodings</span></span>
<span class="line" id="L2"><span class="tok-comment">//! as specified by section 2.4.2 in t-81 1992</span></span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../Image.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">const</span> HuffmanCode = <span class="tok-kw">struct</span> { length_minus_one: <span class="tok-type">u4</span>, code: <span class="tok-type">u16</span> };</span>
<span class="line" id="L12"><span class="tok-kw">const</span> HuffmanCodeMap = std.AutoArrayHashMap(HuffmanCode, <span class="tok-type">u8</span>);</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> JPEG_DEBUG = <span class="tok-null">false</span>;</span>
<span class="line" id="L15"><span class="tok-kw">const</span> JPEG_VERY_DEBUG = <span class="tok-null">false</span>;</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Table = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L18"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"> allocator: Allocator,</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"> code_counts: [<span class="tok-number">16</span>]<span class="tok-type">u8</span>,</span>
<span class="line" id="L23"> code_map: HuffmanCodeMap,</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"> table_class: <span class="tok-type">u8</span>,</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(allocator: Allocator, table_class: <span class="tok-type">u8</span>, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!Self {</span>
<span class="line" id="L28"> <span class="tok-kw">if</span> (table_class &amp; <span class="tok-number">1</span> != table_class)</span>
<span class="line" id="L29"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"> <span class="tok-kw">var</span> code_counts: [<span class="tok-number">16</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L32"> <span class="tok-kw">if</span> ((<span class="tok-kw">try</span> reader.read(code_counts[<span class="tok-number">0</span>..])) &lt; <span class="tok-number">16</span>) {</span>
<span class="line" id="L33"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L34"> }</span>
<span class="line" id="L35"></span>
<span class="line" id="L36"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot; Code counts: {any}\n&quot;</span>, .{code_counts});</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"> <span class="tok-kw">var</span> total_huffman_codes: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L39"> <span class="tok-kw">for</span> (code_counts) |count| total_huffman_codes += count;</span>
<span class="line" id="L40"></span>
<span class="line" id="L41"> <span class="tok-kw">var</span> huffman_code_map = HuffmanCodeMap.init(allocator);</span>
<span class="line" id="L42"> <span class="tok-kw">errdefer</span> huffman_code_map.deinit();</span>
<span class="line" id="L43"></span>
<span class="line" id="L44"> <span class="tok-kw">if</span> (JPEG_VERY_DEBUG) std.debug.print(<span class="tok-str">&quot; Decoded huffman codes map:\n&quot;</span>, .{});</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> <span class="tok-kw">var</span> code: <span class="tok-type">u16</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L47"> <span class="tok-kw">for</span> (code_counts, <span class="tok-number">0</span>..) |count, i| {</span>
<span class="line" id="L48"> <span class="tok-kw">if</span> (JPEG_VERY_DEBUG) {</span>
<span class="line" id="L49"> std.debug.print(<span class="tok-str">&quot; Length {}: &quot;</span>, .{i + <span class="tok-number">1</span>});</span>
<span class="line" id="L50"> <span class="tok-kw">if</span> (count == <span class="tok-number">0</span>) {</span>
<span class="line" id="L51"> std.debug.print(<span class="tok-str">&quot;(none)\n&quot;</span>, .{});</span>
<span class="line" id="L52"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L53"> std.debug.print(<span class="tok-str">&quot;\n&quot;</span>, .{});</span>
<span class="line" id="L54"> }</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56"></span>
<span class="line" id="L57"> <span class="tok-kw">var</span> j: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L58"> <span class="tok-kw">while</span> (j &lt; count) : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L59"> <span class="tok-comment">// Check if we hit all 1s, i.e. 111111 for i == 6, which is an invalid value</span>
</span>
<span class="line" id="L60"> <span class="tok-kw">if</span> (code == (<span class="tok-builtin">@as</span>(<span class="tok-type">u17</span>, <span class="tok-builtin">@intCast</span>(<span class="tok-number">1</span>)) &lt;&lt; (<span class="tok-builtin">@as</span>(<span class="tok-type">u5</span>, <span class="tok-builtin">@intCast</span>(i)) + <span class="tok-number">1</span>)) - <span class="tok-number">1</span>) {</span>
<span class="line" id="L61"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L62"> }</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"> <span class="tok-kw">const</span> byte = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L65"> <span class="tok-kw">try</span> huffman_code_map.put(.{ .length_minus_one = <span class="tok-builtin">@as</span>(<span class="tok-type">u4</span>, <span class="tok-builtin">@intCast</span>(i)), .code = code }, byte);</span>
<span class="line" id="L66"></span>
<span class="line" id="L67"> <span class="tok-kw">if</span> (JPEG_VERY_DEBUG) std.debug.print(<span class="tok-str">&quot; {b} =&gt; 0x{X}\n&quot;</span>, .{ code, byte });</span>
<span class="line" id="L68"> code += <span class="tok-number">1</span>;</span>
<span class="line" id="L69"> }</span>
<span class="line" id="L70"></span>
<span class="line" id="L71"> code &lt;&lt;= <span class="tok-number">1</span>;</span>
<span class="line" id="L72"> }</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"> <span class="tok-kw">return</span> Self{</span>
<span class="line" id="L75"> .allocator = allocator,</span>
<span class="line" id="L76"> .code_counts = code_counts,</span>
<span class="line" id="L77"> .code_map = huffman_code_map,</span>
<span class="line" id="L78"> .table_class = table_class,</span>
<span class="line" id="L79"> };</span>
<span class="line" id="L80"> }</span>
<span class="line" id="L81"></span>
<span class="line" id="L82"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L83"> self.code_map.deinit();</span>
<span class="line" id="L84"> }</span>
<span class="line" id="L85">};</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Reader = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L88"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> table: ?*<span class="tok-kw">const</span> Table = <span class="tok-null">null</span>,</span>
<span class="line" id="L91"> reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader,</span>
<span class="line" id="L92"> byte_buffer: <span class="tok-type">u8</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L93"> bits_left: <span class="tok-type">u4</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L94"> last_byte_was_ff: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L95"></span>
<span class="line" id="L96"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) Self {</span>
<span class="line" id="L97"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L98"> .reader = reader,</span>
<span class="line" id="L99"> };</span>
<span class="line" id="L100"> }</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">setHuffmanTable</span>(self: *Self, table: *<span class="tok-kw">const</span> Table) <span class="tok-type">void</span> {</span>
<span class="line" id="L103"> self.table = table;</span>
<span class="line" id="L104"> }</span>
<span class="line" id="L105"></span>
<span class="line" id="L106"> <span class="tok-kw">fn</span> <span class="tok-fn">readBit</span>(self: *Self) ImageReadError!<span class="tok-type">u1</span> {</span>
<span class="line" id="L107"> <span class="tok-kw">if</span> (self.bits_left == <span class="tok-number">0</span>) {</span>
<span class="line" id="L108"> self.byte_buffer = <span class="tok-kw">try</span> self.reader.readByte();</span>
<span class="line" id="L109"></span>
<span class="line" id="L110"> <span class="tok-kw">if</span> (self.byte_buffer == <span class="tok-number">0</span> <span class="tok-kw">and</span> self.last_byte_was_ff) {</span>
<span class="line" id="L111"> <span class="tok-comment">// This was a stuffed byte, read one more.</span>
</span>
<span class="line" id="L112"> self.byte_buffer = <span class="tok-kw">try</span> self.reader.readByte();</span>
<span class="line" id="L113"> }</span>
<span class="line" id="L114"> self.last_byte_was_ff = self.byte_buffer == <span class="tok-number">0xFF</span>;</span>
<span class="line" id="L115"> self.bits_left = <span class="tok-number">8</span>;</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"> <span class="tok-kw">const</span> bit: <span class="tok-type">u1</span> = <span class="tok-builtin">@intCast</span>(self.byte_buffer &gt;&gt; <span class="tok-number">7</span>);</span>
<span class="line" id="L119"> self.byte_buffer &lt;&lt;= <span class="tok-number">1</span>;</span>
<span class="line" id="L120"> self.bits_left -= <span class="tok-number">1</span>;</span>
<span class="line" id="L121"></span>
<span class="line" id="L122"> <span class="tok-kw">return</span> bit;</span>
<span class="line" id="L123"> }</span>
<span class="line" id="L124"></span>
<span class="line" id="L125"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readCode</span>(self: *Self) ImageReadError!<span class="tok-type">u8</span> {</span>
<span class="line" id="L126"> <span class="tok-kw">var</span> code: <span class="tok-type">u16</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L127"></span>
<span class="line" id="L128"> <span class="tok-kw">var</span> i: <span class="tok-type">u5</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L129"> <span class="tok-kw">while</span> (i &lt; <span class="tok-number">16</span>) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L130"> <span class="tok-comment">// NOTE: if the table is stored as a tree, this is O(1) to update the new node,</span>
</span>
<span class="line" id="L131"> <span class="tok-comment">// instead of O(log n), so should be faster.</span>
</span>
<span class="line" id="L132"> code = (code &lt;&lt; <span class="tok-number">1</span>) | (<span class="tok-kw">try</span> self.readBit());</span>
<span class="line" id="L133"> <span class="tok-kw">if</span> (self.table.?.code_map.get(.{ .length_minus_one = <span class="tok-builtin">@intCast</span>(i), .code = code })) |value| {</span>
<span class="line" id="L134"> <span class="tok-kw">return</span> value;</span>
<span class="line" id="L135"> }</span>
<span class="line" id="L136"> }</span>
<span class="line" id="L137"></span>
<span class="line" id="L138"> <span class="tok-kw">if</span> (JPEG_DEBUG) std.debug.print(<span class="tok-str">&quot;found unknown code: {x}\n&quot;</span>, .{code});</span>
<span class="line" id="L139"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L140"> }</span>
<span class="line" id="L141"></span>
<span class="line" id="L142"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readLiteralBits</span>(self: *Self, bitsNeeded: <span class="tok-type">u8</span>) ImageReadError!<span class="tok-type">u32</span> {</span>
<span class="line" id="L143"> <span class="tok-kw">var</span> bits: <span class="tok-type">u32</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L144"></span>
<span class="line" id="L145"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L146"> <span class="tok-kw">while</span> (i &lt; bitsNeeded) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L147"> bits = (bits &lt;&lt; <span class="tok-number">1</span>) | (<span class="tok-kw">try</span> self.readBit());</span>
<span class="line" id="L148"> }</span>
<span class="line" id="L149"></span>
<span class="line" id="L150"> <span class="tok-kw">return</span> bits;</span>
<span class="line" id="L151"> }</span>
<span class="line" id="L152"></span>
<span class="line" id="L153"> <span class="tok-comment">/// This function implements T.81 section F1.2.1, Huffman encoding of DC coefficients.</span></span>
<span class="line" id="L154"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readMagnitudeCoded</span>(self: *Self, magnitude: <span class="tok-type">u5</span>) ImageReadError!<span class="tok-type">i32</span> {</span>
<span class="line" id="L155"> <span class="tok-kw">if</span> (magnitude == <span class="tok-number">0</span>)</span>
<span class="line" id="L156"> <span class="tok-kw">return</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"> <span class="tok-kw">const</span> bits = <span class="tok-kw">try</span> self.readLiteralBits(magnitude);</span>
<span class="line" id="L159"></span>
<span class="line" id="L160"> <span class="tok-comment">// The sign of the read bits value.</span>
</span>
<span class="line" id="L161"> <span class="tok-kw">const</span> bits_sign = (bits &gt;&gt; (magnitude - <span class="tok-number">1</span>)) &amp; <span class="tok-number">1</span>;</span>
<span class="line" id="L162"> <span class="tok-comment">// The mask for clearing the sign bit.</span>
</span>
<span class="line" id="L163"> <span class="tok-kw">const</span> bits_mask = (<span class="tok-builtin">@as</span>(<span class="tok-type">u32</span>, <span class="tok-number">1</span>) &lt;&lt; (magnitude - <span class="tok-number">1</span>)) - <span class="tok-number">1</span>;</span>
<span class="line" id="L164"> <span class="tok-comment">// The bits without the sign bit.</span>
</span>
<span class="line" id="L165"> <span class="tok-kw">const</span> unsigned_bits = bits &amp; bits_mask;</span>
<span class="line" id="L166"></span>
<span class="line" id="L167"> <span class="tok-comment">// The magnitude base value. This is -2^n+1 when bits_sign == 0, and</span>
</span>
<span class="line" id="L168"> <span class="tok-comment">// 2^(n-1) when bits_sign == 1.</span>
</span>
<span class="line" id="L169"> <span class="tok-kw">const</span> base = <span class="tok-kw">if</span> (bits_sign == <span class="tok-number">0</span>)</span>
<span class="line" id="L170"> -(<span class="tok-builtin">@as</span>(<span class="tok-type">i32</span>, <span class="tok-number">1</span>) &lt;&lt; magnitude) + <span class="tok-number">1</span></span>
<span class="line" id="L171"> <span class="tok-kw">else</span></span>
<span class="line" id="L172"> (<span class="tok-builtin">@as</span>(<span class="tok-type">i32</span>, <span class="tok-number">1</span>) &lt;&lt; (magnitude - <span class="tok-number">1</span>));</span>
<span class="line" id="L173"></span>
<span class="line" id="L174"> <span class="tok-kw">return</span> base + <span class="tok-builtin">@as</span>(<span class="tok-type">i32</span>, <span class="tok-builtin">@bitCast</span>(unsigned_bits));</span>
<span class="line" id="L175"> }</span>
<span class="line" id="L176">};</span>
<span class="line" id="L177"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,213 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/jpeg/quantization.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! see section 2.4.1 of the spec t-81 1992</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../Image.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> ZigzagOffsets = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;./utils.zig&quot;</span>).ZigzagOffsets;</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">const</span> JPEG_DEBUG = <span class="tok-null">false</span>;</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Header = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L14"> <span class="tok-comment">// TODO(angelo): ! substitute this implementation to `parseDefineQuantizationTables` in jpeg.zig</span>
</span>
<span class="line" id="L15"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"> <span class="tok-comment">//// Specifies the precision of the quantization table entries.</span>
</span>
<span class="line" id="L18"> <span class="tok-comment">/// - 0 = 8 bits</span></span>
<span class="line" id="L19"> <span class="tok-comment">/// - 1 = 16 bits</span></span>
<span class="line" id="L20"> table_precision: <span class="tok-type">u4</span>,</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"> <span class="tok-comment">/// Specifies one of four possible destinations at the decoder into</span></span>
<span class="line" id="L23"> <span class="tok-comment">/// which the quantization table shall be installed.</span></span>
<span class="line" id="L24"> table_destination: <span class="tok-type">u4</span>,</span>
<span class="line" id="L25"></span>
<span class="line" id="L26"> table: Table,</span>
<span class="line" id="L27"></span>
<span class="line" id="L28"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!Self {</span>
<span class="line" id="L29"> _ = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big); <span class="tok-comment">// read the size, but we don't need it</span>
</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"> <span class="tok-kw">const</span> precision_and_destination = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L32"> <span class="tok-kw">const</span> table_precision = precision_and_destination &gt;&gt; <span class="tok-number">4</span>;</span>
<span class="line" id="L33"> <span class="tok-kw">const</span> table_destination = precision_and_destination &amp; <span class="tok-number">0b11</span>;</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"> <span class="tok-kw">const</span> table = <span class="tok-kw">try</span> Table.read(table_precision, reader);</span>
<span class="line" id="L36"></span>
<span class="line" id="L37"> <span class="tok-comment">// TODO: add check for: &quot;An 8-bit DCT-based process shall not use a 16-bit precision quantization table.&quot;</span>
</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"> <span class="tok-kw">return</span> Self{</span>
<span class="line" id="L40"> .table_precision = table_precision,</span>
<span class="line" id="L41"> .table_destination = table_destination,</span>
<span class="line" id="L42"> .table = table,</span>
<span class="line" id="L43"> };</span>
<span class="line" id="L44"> }</span>
<span class="line" id="L45">};</span>
<span class="line" id="L46"></span>
<span class="line" id="L47"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Table = <span class="tok-kw">union</span>(<span class="tok-kw">enum</span>) {</span>
<span class="line" id="L48"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L49"> q8: [<span class="tok-number">64</span>]<span class="tok-type">u8</span>,</span>
<span class="line" id="L50"> q16: [<span class="tok-number">64</span>]<span class="tok-type">u16</span>,</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(precision: <span class="tok-type">u8</span>, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!Self {</span>
<span class="line" id="L53"> <span class="tok-comment">// 0 = 8 bits, 1 = 16 bits</span>
</span>
<span class="line" id="L54"> <span class="tok-kw">switch</span> (precision) {</span>
<span class="line" id="L55"> <span class="tok-number">0</span> =&gt; {</span>
<span class="line" id="L56"> <span class="tok-kw">var</span> table = Self{ .q8 = <span class="tok-null">undefined</span> };</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L59"> <span class="tok-kw">while</span> (offset &lt; <span class="tok-number">64</span>) : (offset += <span class="tok-number">1</span>) {</span>
<span class="line" id="L60"> <span class="tok-kw">const</span> value = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L61"> table.q8[ZigzagOffsets[offset]] = value;</span>
<span class="line" id="L62"> }</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"> <span class="tok-kw">if</span> (JPEG_DEBUG) {</span>
<span class="line" id="L65"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L66"> <span class="tok-kw">while</span> (i &lt; <span class="tok-number">8</span>) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L67"> <span class="tok-kw">var</span> j: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L68"> <span class="tok-kw">while</span> (j &lt; <span class="tok-number">8</span>) : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L69"> std.debug.print(<span class="tok-str">&quot;{d:4} &quot;</span>, .{table.q8[i * <span class="tok-number">8</span> + j]});</span>
<span class="line" id="L70"> }</span>
<span class="line" id="L71"> std.debug.print(<span class="tok-str">&quot;\n&quot;</span>, .{});</span>
<span class="line" id="L72"> }</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> <span class="tok-kw">return</span> table;</span>
<span class="line" id="L76"> },</span>
<span class="line" id="L77"> <span class="tok-number">1</span> =&gt; {</span>
<span class="line" id="L78"> <span class="tok-kw">var</span> table = Self{ .q16 = <span class="tok-null">undefined</span> };</span>
<span class="line" id="L79"></span>
<span class="line" id="L80"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L81"> <span class="tok-kw">while</span> (offset &lt; <span class="tok-number">64</span>) : (offset += <span class="tok-number">1</span>) {</span>
<span class="line" id="L82"> <span class="tok-kw">const</span> value = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big);</span>
<span class="line" id="L83"> table.q16[ZigzagOffsets[offset]] = value;</span>
<span class="line" id="L84"> }</span>
<span class="line" id="L85"></span>
<span class="line" id="L86"> <span class="tok-kw">return</span> table;</span>
<span class="line" id="L87"> },</span>
<span class="line" id="L88"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> ImageReadError.InvalidData,</span>
<span class="line" id="L89"> }</span>
<span class="line" id="L90"> }</span>
<span class="line" id="L91">};</span>
<span class="line" id="L92"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,282 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/jpeg/utils.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! general utilizies and constants</span></span>
<span class="line" id="L2"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-comment">// See figure A.6 in T.81.</span>
</span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ZigzagOffsets = blk: {</span>
<span class="line" id="L6"> <span class="tok-kw">var</span> offsets: [<span class="tok-number">64</span>]<span class="tok-type">usize</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L7"> offsets[<span class="tok-number">0</span>] = <span class="tok-number">0</span>;</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"> <span class="tok-kw">var</span> current_offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L10"> <span class="tok-kw">var</span> direction: <span class="tok-kw">enum</span> { north_east, south_west } = .north_east;</span>
<span class="line" id="L11"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L12"> <span class="tok-kw">while</span> (i &lt; <span class="tok-number">64</span>) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L13"> <span class="tok-kw">switch</span> (direction) {</span>
<span class="line" id="L14"> .north_east =&gt; {</span>
<span class="line" id="L15"> <span class="tok-kw">if</span> (current_offset &lt; <span class="tok-number">8</span>) {</span>
<span class="line" id="L16"> <span class="tok-comment">// Hit top edge</span>
</span>
<span class="line" id="L17"> current_offset += <span class="tok-number">1</span>;</span>
<span class="line" id="L18"> direction = .south_west;</span>
<span class="line" id="L19"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (current_offset % <span class="tok-number">8</span> == <span class="tok-number">7</span>) {</span>
<span class="line" id="L20"> <span class="tok-comment">// Hit right edge</span>
</span>
<span class="line" id="L21"> current_offset += <span class="tok-number">8</span>;</span>
<span class="line" id="L22"> direction = .south_west;</span>
<span class="line" id="L23"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L24"> current_offset -= <span class="tok-number">7</span>;</span>
<span class="line" id="L25"> }</span>
<span class="line" id="L26"> },</span>
<span class="line" id="L27"> .south_west =&gt; {</span>
<span class="line" id="L28"> <span class="tok-kw">if</span> (current_offset &gt;= <span class="tok-number">56</span>) {</span>
<span class="line" id="L29"> <span class="tok-comment">// Hit bottom edge</span>
</span>
<span class="line" id="L30"> current_offset += <span class="tok-number">1</span>;</span>
<span class="line" id="L31"> direction = .north_east;</span>
<span class="line" id="L32"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (current_offset % <span class="tok-number">8</span> == <span class="tok-number">0</span>) {</span>
<span class="line" id="L33"> <span class="tok-comment">// Hit left edge</span>
</span>
<span class="line" id="L34"> current_offset += <span class="tok-number">8</span>;</span>
<span class="line" id="L35"> direction = .north_east;</span>
<span class="line" id="L36"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L37"> current_offset += <span class="tok-number">7</span>;</span>
<span class="line" id="L38"> }</span>
<span class="line" id="L39"> },</span>
<span class="line" id="L40"> }</span>
<span class="line" id="L41"></span>
<span class="line" id="L42"> <span class="tok-kw">if</span> (current_offset &gt;= <span class="tok-number">64</span>) {</span>
<span class="line" id="L43"> <span class="tok-builtin">@compileError</span>(std.fmt.comptimePrint(<span class="tok-str">&quot;ZigzagOffsets: Hit offset {} (&gt;= 64) at index {}!\n&quot;</span>, .{ current_offset, i }));</span>
<span class="line" id="L44"> }</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> offsets[i] = current_offset;</span>
<span class="line" id="L47"> }</span>
<span class="line" id="L48"></span>
<span class="line" id="L49"> <span class="tok-kw">break</span> :blk offsets;</span>
<span class="line" id="L50">};</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"><span class="tok-comment">/// The precalculated IDCT multipliers. This is possible because the only part of</span></span>
<span class="line" id="L53"><span class="tok-comment">/// the IDCT calculation that changes between runs is the coefficients.</span></span>
<span class="line" id="L54"><span class="tok-comment">/// see A.3.3 of t.81 1992</span></span>
<span class="line" id="L55"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> IDCTMultipliers = blk: {</span>
<span class="line" id="L56"> <span class="tok-kw">var</span> multipliers: [<span class="tok-number">8</span>][<span class="tok-number">8</span>][<span class="tok-number">8</span>][<span class="tok-number">8</span>]<span class="tok-type">f32</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L57"> <span class="tok-builtin">@setEvalBranchQuota</span>(<span class="tok-number">4700</span>);</span>
<span class="line" id="L58"></span>
<span class="line" id="L59"> <span class="tok-kw">var</span> y: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L60"> <span class="tok-kw">while</span> (y &lt; <span class="tok-number">8</span>) : (y += <span class="tok-number">1</span>) {</span>
<span class="line" id="L61"> <span class="tok-kw">var</span> x: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L62"> <span class="tok-kw">while</span> (x &lt; <span class="tok-number">8</span>) : (x += <span class="tok-number">1</span>) {</span>
<span class="line" id="L63"> <span class="tok-kw">var</span> u: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L64"> <span class="tok-kw">while</span> (u &lt; <span class="tok-number">8</span>) : (u += <span class="tok-number">1</span>) {</span>
<span class="line" id="L65"> <span class="tok-kw">var</span> v: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L66"> <span class="tok-kw">while</span> (v &lt; <span class="tok-number">8</span>) : (v += <span class="tok-number">1</span>) {</span>
<span class="line" id="L67"> <span class="tok-kw">const</span> C_u: <span class="tok-type">f32</span> = <span class="tok-kw">if</span> (u == <span class="tok-number">0</span>) <span class="tok-number">1.0</span> / <span class="tok-builtin">@sqrt</span>(<span class="tok-number">2.0</span>) <span class="tok-kw">else</span> <span class="tok-number">1.0</span>;</span>
<span class="line" id="L68"> <span class="tok-kw">const</span> C_v: <span class="tok-type">f32</span> = <span class="tok-kw">if</span> (v == <span class="tok-number">0</span>) <span class="tok-number">1.0</span> / <span class="tok-builtin">@sqrt</span>(<span class="tok-number">2.0</span>) <span class="tok-kw">else</span> <span class="tok-number">1.0</span>;</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-kw">const</span> x_cosine = <span class="tok-builtin">@cos</span>(((<span class="tok-number">2</span> * <span class="tok-builtin">@as</span>(<span class="tok-type">f32</span>, <span class="tok-builtin">@floatFromInt</span>(x)) + <span class="tok-number">1</span>) * <span class="tok-builtin">@as</span>(<span class="tok-type">f32</span>, <span class="tok-builtin">@floatFromInt</span>(u)) * std.math.pi) / <span class="tok-number">16.0</span>);</span>
<span class="line" id="L71"> <span class="tok-kw">const</span> y_cosine = <span class="tok-builtin">@cos</span>(((<span class="tok-number">2</span> * <span class="tok-builtin">@as</span>(<span class="tok-type">f32</span>, <span class="tok-builtin">@floatFromInt</span>(y)) + <span class="tok-number">1</span>) * <span class="tok-builtin">@as</span>(<span class="tok-type">f32</span>, <span class="tok-builtin">@floatFromInt</span>(v)) * std.math.pi) / <span class="tok-number">16.0</span>);</span>
<span class="line" id="L72"> <span class="tok-kw">const</span> uv_value = C_u * C_v * x_cosine * y_cosine;</span>
<span class="line" id="L73"> multipliers[y][x][u][v] = uv_value;</span>
<span class="line" id="L74"> }</span>
<span class="line" id="L75"> }</span>
<span class="line" id="L76"> }</span>
<span class="line" id="L77"> }</span>
<span class="line" id="L78"></span>
<span class="line" id="L79"> <span class="tok-kw">break</span> :blk multipliers;</span>
<span class="line" id="L80">};</span>
<span class="line" id="L81"></span>
<span class="line" id="L82"><span class="tok-comment">/// Marker codes, see t-81 section B.1.1.3</span></span>
<span class="line" id="L83"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Markers = <span class="tok-kw">enum</span>(<span class="tok-type">u16</span>) {</span>
<span class="line" id="L84"> <span class="tok-comment">// Start of Frame markers, non-differential, Huffman coding</span>
</span>
<span class="line" id="L85"> sof0 = <span class="tok-number">0xFFC0</span>, <span class="tok-comment">// Baseline DCT</span>
</span>
<span class="line" id="L86"> sof1 = <span class="tok-number">0xFFC1</span>, <span class="tok-comment">// Extended sequential DCT</span>
</span>
<span class="line" id="L87"> sof2 = <span class="tok-number">0xFFC2</span>, <span class="tok-comment">// Progressive DCT</span>
</span>
<span class="line" id="L88"> sof3 = <span class="tok-number">0xFFC3</span>, <span class="tok-comment">// Lossless sequential</span>
</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> <span class="tok-comment">// Start of Frame markers, differential, Huffman coding</span>
</span>
<span class="line" id="L91"> sof5 = <span class="tok-number">0xFFC5</span>, <span class="tok-comment">// Differential sequential DCT</span>
</span>
<span class="line" id="L92"> sof6 = <span class="tok-number">0xFFC6</span>, <span class="tok-comment">// Differential progressive DCT</span>
</span>
<span class="line" id="L93"> sof7 = <span class="tok-number">0xFFC7</span>, <span class="tok-comment">// Differential lossless sequential</span>
</span>
<span class="line" id="L94"></span>
<span class="line" id="L95"> <span class="tok-comment">// Start of Frame markers, non-differential, arithmetic coding</span>
</span>
<span class="line" id="L96"> sof9 = <span class="tok-number">0xFFC9</span>, <span class="tok-comment">// Extended sequential DCT</span>
</span>
<span class="line" id="L97"> sof10 = <span class="tok-number">0xFFCA</span>, <span class="tok-comment">// Progressive DCT</span>
</span>
<span class="line" id="L98"> sof11 = <span class="tok-number">0xFFCB</span>, <span class="tok-comment">// Lossless sequential</span>
</span>
<span class="line" id="L99"></span>
<span class="line" id="L100"> <span class="tok-comment">// Start of Frame markers, differential, arithmetic coding</span>
</span>
<span class="line" id="L101"> sof13 = <span class="tok-number">0xFFCD</span>, <span class="tok-comment">// Differential sequential DCT</span>
</span>
<span class="line" id="L102"> sof14 = <span class="tok-number">0xFFCE</span>, <span class="tok-comment">// Differential progressive DCT</span>
</span>
<span class="line" id="L103"> sof15 = <span class="tok-number">0xFFCF</span>, <span class="tok-comment">// Differential lossless sequential</span>
</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"> define_huffman_tables = <span class="tok-number">0xFFC4</span>,</span>
<span class="line" id="L106"> define_arithmetic_coding = <span class="tok-number">0xFFCC</span>,</span>
<span class="line" id="L107"></span>
<span class="line" id="L108"> <span class="tok-comment">// 0xFFD0-0xFFD7: Restart markers</span>
</span>
<span class="line" id="L109"> restart0 = <span class="tok-number">0xFFD0</span>,</span>
<span class="line" id="L110"> restart1 = <span class="tok-number">0xFFD1</span>,</span>
<span class="line" id="L111"> restart2 = <span class="tok-number">0xFFD2</span>,</span>
<span class="line" id="L112"> restart3 = <span class="tok-number">0xFFD3</span>,</span>
<span class="line" id="L113"> restart4 = <span class="tok-number">0xFFD4</span>,</span>
<span class="line" id="L114"> restart5 = <span class="tok-number">0xFFD5</span>,</span>
<span class="line" id="L115"> restart6 = <span class="tok-number">0xFFD6</span>,</span>
<span class="line" id="L116"> restart7 = <span class="tok-number">0xFFD7</span>,</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"> start_of_image = <span class="tok-number">0xFFD8</span>,</span>
<span class="line" id="L119"> end_of_image = <span class="tok-number">0xFFD9</span>,</span>
<span class="line" id="L120"> start_of_scan = <span class="tok-number">0xFFDA</span>,</span>
<span class="line" id="L121"> define_quantization_tables = <span class="tok-number">0xFFDB</span>,</span>
<span class="line" id="L122"> define_number_of_lines = <span class="tok-number">0xFFDC</span>,</span>
<span class="line" id="L123"> define_restart_interval = <span class="tok-number">0xFFDD</span>,</span>
<span class="line" id="L124"> define_hierarchical_progression = <span class="tok-number">0xFFDE</span>,</span>
<span class="line" id="L125"> expand_reference_components = <span class="tok-number">0xFFDF</span>,</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"> <span class="tok-comment">// 0xFFE0-0xFFEF application segments markers add 0-15 as needed.</span>
</span>
<span class="line" id="L128"> application0 = <span class="tok-number">0xFFE0</span>,</span>
<span class="line" id="L129"></span>
<span class="line" id="L130"> <span class="tok-comment">// 0xFFF0-0xFFFD jpeg extension markers add 0-13 as needed.</span>
</span>
<span class="line" id="L131"> jpeg_extension0 = <span class="tok-number">0xFFF0</span>,</span>
<span class="line" id="L132"> comment = <span class="tok-number">0xFFFE</span>,</span>
<span class="line" id="L133"></span>
<span class="line" id="L134"> <span class="tok-comment">// reserved markers from 0xFF01-0xFFBF, add as needed</span>
</span>
<span class="line" id="L135">};</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> MAX_COMPONENTS = <span class="tok-number">3</span>;</span>
<span class="line" id="L138"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> MAX_BLOCKS = <span class="tok-number">8</span>;</span>
<span class="line" id="L139"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> MCU = [<span class="tok-number">64</span>]<span class="tok-type">i32</span>;</span>
<span class="line" id="L140"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,635 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/netpbm.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Adapted from https://github.com/MasterQ32/zig-gamedev-lib/blob/master/src/netbpm.zig</span>
</span>
<span class="line" id="L2"><span class="tok-comment">// with permission from Felix Queißner</span>
</span>
<span class="line" id="L3"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../color.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> ImageError = Image.Error;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L10"><span class="tok-kw">const</span> ImageWriteError = Image.WriteError;</span>
<span class="line" id="L11"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L12"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L13"><span class="tok-kw">const</span> utils = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../utils.zig&quot;</span>);</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-comment">// this file implements the Portable Anymap specification provided by</span>
</span>
<span class="line" id="L16"><span class="tok-comment">// http://netpbm.sourceforge.net/doc/pbm.html // P1, P4 =&gt; bitmap</span>
</span>
<span class="line" id="L17"><span class="tok-comment">// http://netpbm.sourceforge.net/doc/pgm.html // P2, P5 =&gt; graymap</span>
</span>
<span class="line" id="L18"><span class="tok-comment">// http://netpbm.sourceforge.net/doc/ppm.html // P3, P6 =&gt; pixmap</span>
</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-comment">/// one of the three types a netbpm graphic could be stored in.</span></span>
<span class="line" id="L21"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Format = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L22"> <span class="tok-comment">/// the image contains black-and-white pixels.</span></span>
<span class="line" id="L23"> bitmap,</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"> <span class="tok-comment">/// the image contains grayscale pixels.</span></span>
<span class="line" id="L26"> grayscale,</span>
<span class="line" id="L27"></span>
<span class="line" id="L28"> <span class="tok-comment">/// the image contains RGB pixels.</span></span>
<span class="line" id="L29"> rgb,</span>
<span class="line" id="L30">};</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Header = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L33"> format: Format,</span>
<span class="line" id="L34"> binary: <span class="tok-type">bool</span>,</span>
<span class="line" id="L35"> width: <span class="tok-type">usize</span>,</span>
<span class="line" id="L36"> height: <span class="tok-type">usize</span>,</span>
<span class="line" id="L37"> max_value: <span class="tok-type">usize</span>,</span>
<span class="line" id="L38">};</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"><span class="tok-kw">fn</span> <span class="tok-fn">parseHeader</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!Header {</span>
<span class="line" id="L41"> <span class="tok-kw">var</span> header: Header = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"> <span class="tok-kw">var</span> magic: [<span class="tok-number">2</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L44"> _ = <span class="tok-kw">try</span> reader.read(magic[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, &amp;magic, <span class="tok-str">&quot;P1&quot;</span>)) {</span>
<span class="line" id="L47"> header.binary = <span class="tok-null">false</span>;</span>
<span class="line" id="L48"> header.format = .bitmap;</span>
<span class="line" id="L49"> header.max_value = <span class="tok-number">1</span>;</span>
<span class="line" id="L50"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, &amp;magic, <span class="tok-str">&quot;P2&quot;</span>)) {</span>
<span class="line" id="L51"> header.binary = <span class="tok-null">false</span>;</span>
<span class="line" id="L52"> header.format = .grayscale;</span>
<span class="line" id="L53"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, &amp;magic, <span class="tok-str">&quot;P3&quot;</span>)) {</span>
<span class="line" id="L54"> header.binary = <span class="tok-null">false</span>;</span>
<span class="line" id="L55"> header.format = .rgb;</span>
<span class="line" id="L56"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, &amp;magic, <span class="tok-str">&quot;P4&quot;</span>)) {</span>
<span class="line" id="L57"> header.binary = <span class="tok-null">true</span>;</span>
<span class="line" id="L58"> header.format = .bitmap;</span>
<span class="line" id="L59"> header.max_value = <span class="tok-number">1</span>;</span>
<span class="line" id="L60"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, &amp;magic, <span class="tok-str">&quot;P5&quot;</span>)) {</span>
<span class="line" id="L61"> header.binary = <span class="tok-null">true</span>;</span>
<span class="line" id="L62"> header.format = .grayscale;</span>
<span class="line" id="L63"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, &amp;magic, <span class="tok-str">&quot;P6&quot;</span>)) {</span>
<span class="line" id="L64"> header.binary = <span class="tok-null">true</span>;</span>
<span class="line" id="L65"> header.format = .rgb;</span>
<span class="line" id="L66"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L67"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-kw">var</span> read_buffer: [<span class="tok-number">16</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L71"></span>
<span class="line" id="L72"> header.width = <span class="tok-kw">try</span> parseNumber(reader, read_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L73"> header.height = <span class="tok-kw">try</span> parseNumber(reader, read_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L74"> <span class="tok-kw">if</span> (header.format != .bitmap) {</span>
<span class="line" id="L75"> header.max_value = <span class="tok-kw">try</span> parseNumber(reader, read_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L76"> }</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> <span class="tok-kw">return</span> header;</span>
<span class="line" id="L79">}</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"><span class="tok-kw">fn</span> <span class="tok-fn">isWhitespace</span>(b: <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L82"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (b) {</span>
<span class="line" id="L83"> <span class="tok-comment">// Whitespace (blanks, TABs, CRs, LFs).</span>
</span>
<span class="line" id="L84"> <span class="tok-str">'\n'</span>, <span class="tok-str">'\r'</span>, <span class="tok-str">' '</span>, <span class="tok-str">'\t'</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L85"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">false</span>,</span>
<span class="line" id="L86"> };</span>
<span class="line" id="L87">}</span>
<span class="line" id="L88"></span>
<span class="line" id="L89"><span class="tok-kw">fn</span> <span class="tok-fn">readNextByte</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">u8</span> {</span>
<span class="line" id="L90"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L91"> <span class="tok-kw">const</span> b = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L92"> <span class="tok-kw">switch</span> (b) {</span>
<span class="line" id="L93"> <span class="tok-comment">// Before the whitespace character that delimits the raster, any characters</span>
</span>
<span class="line" id="L94"> <span class="tok-comment">// from a &quot;#&quot; through the next carriage return or newline character, is a</span>
</span>
<span class="line" id="L95"> <span class="tok-comment">// comment and is ignored. Note that this is rather unconventional, because</span>
</span>
<span class="line" id="L96"> <span class="tok-comment">// a comment can actually be in the middle of what you might consider a token.</span>
</span>
<span class="line" id="L97"> <span class="tok-comment">// Note also that this means if you have a comment right before the raster,</span>
</span>
<span class="line" id="L98"> <span class="tok-comment">// the newline at the end of the comment is not sufficient to delimit the raster.</span>
</span>
<span class="line" id="L99"> <span class="tok-str">'#'</span> =&gt; {</span>
<span class="line" id="L100"> <span class="tok-comment">// eat up comment</span>
</span>
<span class="line" id="L101"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L102"> <span class="tok-kw">const</span> c = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L103"> <span class="tok-kw">switch</span> (c) {</span>
<span class="line" id="L104"> <span class="tok-str">'\r'</span>, <span class="tok-str">'\n'</span> =&gt; <span class="tok-kw">break</span>,</span>
<span class="line" id="L105"> <span class="tok-kw">else</span> =&gt; {},</span>
<span class="line" id="L106"> }</span>
<span class="line" id="L107"> }</span>
<span class="line" id="L108"> },</span>
<span class="line" id="L109"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> b,</span>
<span class="line" id="L110"> }</span>
<span class="line" id="L111"> }</span>
<span class="line" id="L112">}</span>
<span class="line" id="L113"></span>
<span class="line" id="L114"><span class="tok-comment">/// skips whitespace and comments, then reads a number from the stream.</span></span>
<span class="line" id="L115"><span class="tok-comment">/// this function reads one whitespace behind the number as a terminator.</span></span>
<span class="line" id="L116"><span class="tok-kw">fn</span> <span class="tok-fn">parseNumber</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader, buffer: []<span class="tok-type">u8</span>) ImageReadError!<span class="tok-type">usize</span> {</span>
<span class="line" id="L117"> <span class="tok-kw">var</span> input_length: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L118"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L119"> <span class="tok-kw">const</span> b = <span class="tok-kw">try</span> readNextByte(reader);</span>
<span class="line" id="L120"> <span class="tok-kw">if</span> (isWhitespace(b)) {</span>
<span class="line" id="L121"> <span class="tok-kw">if</span> (input_length &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L122"> <span class="tok-kw">return</span> std.fmt.parseInt(<span class="tok-type">usize</span>, buffer[<span class="tok-number">0</span>..input_length], <span class="tok-number">10</span>) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L123"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L124"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L125"> }</span>
<span class="line" id="L126"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L127"> <span class="tok-kw">if</span> (input_length &gt;= buffer.len)</span>
<span class="line" id="L128"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.OutOfMemory;</span>
<span class="line" id="L129"> buffer[input_length] = b;</span>
<span class="line" id="L130"> input_length += <span class="tok-number">1</span>;</span>
<span class="line" id="L131"> }</span>
<span class="line" id="L132"> }</span>
<span class="line" id="L133">}</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"><span class="tok-kw">fn</span> <span class="tok-fn">loadBinaryBitmap</span>(header: Header, data: []color.Grayscale1, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L136"> <span class="tok-kw">var</span> bit_reader = std.io.bitReader(.big, reader);</span>
<span class="line" id="L137"></span>
<span class="line" id="L138"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..header.height) |row_index| {</span>
<span class="line" id="L139"> <span class="tok-kw">for</span> (data[row_index * header.width ..][<span class="tok-number">0</span>..header.width]) |*sample| {</span>
<span class="line" id="L140"> sample.value = ~(<span class="tok-kw">try</span> bit_reader.readBitsNoEof(<span class="tok-type">u1</span>, <span class="tok-number">1</span>));</span>
<span class="line" id="L141"> }</span>
<span class="line" id="L142"> bit_reader.alignToByte();</span>
<span class="line" id="L143"> }</span>
<span class="line" id="L144">}</span>
<span class="line" id="L145"></span>
<span class="line" id="L146"><span class="tok-kw">fn</span> <span class="tok-fn">loadAsciiBitmap</span>(header: Header, data: []color.Grayscale1, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L147"> <span class="tok-kw">var</span> data_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L148"> <span class="tok-kw">const</span> data_end = header.width * header.height;</span>
<span class="line" id="L149"></span>
<span class="line" id="L150"> <span class="tok-kw">while</span> (data_index &lt; data_end) {</span>
<span class="line" id="L151"> <span class="tok-kw">const</span> b = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L152"> <span class="tok-kw">if</span> (isWhitespace(b)) {</span>
<span class="line" id="L153"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L154"> }</span>
<span class="line" id="L155"></span>
<span class="line" id="L156"> <span class="tok-comment">// 1 is black, 0 is white in PBM spec.</span>
</span>
<span class="line" id="L157"> <span class="tok-comment">// we use 1=white, 0=black in u1 format</span>
</span>
<span class="line" id="L158"> <span class="tok-kw">const</span> pixel = <span class="tok-kw">if</span> (b == <span class="tok-str">'0'</span>) <span class="tok-builtin">@as</span>(<span class="tok-type">u1</span>, <span class="tok-number">1</span>) <span class="tok-kw">else</span> <span class="tok-builtin">@as</span>(<span class="tok-type">u1</span>, <span class="tok-number">0</span>);</span>
<span class="line" id="L159"> data[data_index] = color.Grayscale1{ .value = pixel };</span>
<span class="line" id="L160"></span>
<span class="line" id="L161"> data_index += <span class="tok-number">1</span>;</span>
<span class="line" id="L162"> }</span>
<span class="line" id="L163">}</span>
<span class="line" id="L164"></span>
<span class="line" id="L165"><span class="tok-kw">fn</span> <span class="tok-fn">readLinearizedValue</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader, max_value: <span class="tok-type">usize</span>) ImageReadError!<span class="tok-type">u8</span> {</span>
<span class="line" id="L166"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (max_value &gt; <span class="tok-number">255</span>)</span>
<span class="line" id="L167"> <span class="tok-builtin">@truncate</span>(<span class="tok-number">255</span> * <span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big)) / max_value)</span>
<span class="line" id="L168"> <span class="tok-kw">else</span></span>
<span class="line" id="L169"> <span class="tok-builtin">@truncate</span>(<span class="tok-number">255</span> * <span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-kw">try</span> reader.readByte()) / max_value);</span>
<span class="line" id="L170">}</span>
<span class="line" id="L171"></span>
<span class="line" id="L172"><span class="tok-kw">fn</span> <span class="tok-fn">loadBinaryGraymap</span>(header: Header, pixels: *color.PixelStorage, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L173"> <span class="tok-kw">var</span> data_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L174"> <span class="tok-kw">const</span> data_end = header.width * header.height;</span>
<span class="line" id="L175"> <span class="tok-kw">if</span> (header.max_value &lt;= <span class="tok-number">255</span>) {</span>
<span class="line" id="L176"> <span class="tok-kw">while</span> (data_index &lt; data_end) : (data_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L177"> pixels.grayscale8[data_index] = color.Grayscale8{ .value = <span class="tok-kw">try</span> readLinearizedValue(reader, header.max_value) };</span>
<span class="line" id="L178"> }</span>
<span class="line" id="L179"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L180"> <span class="tok-kw">while</span> (data_index &lt; data_end) : (data_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L181"> pixels.grayscale16[data_index] = color.Grayscale16{ .value = <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .big) };</span>
<span class="line" id="L182"> }</span>
<span class="line" id="L183"> }</span>
<span class="line" id="L184">}</span>
<span class="line" id="L185"></span>
<span class="line" id="L186"><span class="tok-kw">fn</span> <span class="tok-fn">loadAsciiGraymap</span>(header: Header, pixels: *color.PixelStorage, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L187"> <span class="tok-kw">var</span> read_buffer: [<span class="tok-number">16</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L188"></span>
<span class="line" id="L189"> <span class="tok-kw">var</span> data_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L190"> <span class="tok-kw">const</span> data_end = header.width * header.height;</span>
<span class="line" id="L191"></span>
<span class="line" id="L192"> <span class="tok-kw">if</span> (header.max_value &lt;= <span class="tok-number">255</span>) {</span>
<span class="line" id="L193"> <span class="tok-kw">while</span> (data_index &lt; data_end) : (data_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L194"> pixels.grayscale8[data_index] = color.Grayscale8{ .value = <span class="tok-builtin">@truncate</span>(<span class="tok-kw">try</span> parseNumber(reader, read_buffer[<span class="tok-number">0</span>..])) };</span>
<span class="line" id="L195"> }</span>
<span class="line" id="L196"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L197"> <span class="tok-kw">while</span> (data_index &lt; data_end) : (data_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L198"> pixels.grayscale16[data_index] = color.Grayscale16{ .value = <span class="tok-builtin">@truncate</span>(<span class="tok-kw">try</span> parseNumber(reader, read_buffer[<span class="tok-number">0</span>..])) };</span>
<span class="line" id="L199"> }</span>
<span class="line" id="L200"> }</span>
<span class="line" id="L201">}</span>
<span class="line" id="L202"></span>
<span class="line" id="L203"><span class="tok-kw">fn</span> <span class="tok-fn">loadBinaryRgbmap</span>(header: Header, data: []color.Rgb24, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L204"> <span class="tok-kw">var</span> data_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L205"> <span class="tok-kw">const</span> data_end = header.width * header.height;</span>
<span class="line" id="L206"></span>
<span class="line" id="L207"> <span class="tok-kw">while</span> (data_index &lt; data_end) : (data_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L208"> data[data_index] = color.Rgb24{</span>
<span class="line" id="L209"> .r = <span class="tok-kw">try</span> readLinearizedValue(reader, header.max_value),</span>
<span class="line" id="L210"> .g = <span class="tok-kw">try</span> readLinearizedValue(reader, header.max_value),</span>
<span class="line" id="L211"> .b = <span class="tok-kw">try</span> readLinearizedValue(reader, header.max_value),</span>
<span class="line" id="L212"> };</span>
<span class="line" id="L213"> }</span>
<span class="line" id="L214">}</span>
<span class="line" id="L215"></span>
<span class="line" id="L216"><span class="tok-kw">fn</span> <span class="tok-fn">loadAsciiRgbmap</span>(header: Header, data: []color.Rgb24, reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L217"> <span class="tok-kw">var</span> read_buffer: [<span class="tok-number">16</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L218"></span>
<span class="line" id="L219"> <span class="tok-kw">var</span> data_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L220"> <span class="tok-kw">const</span> data_end = header.width * header.height;</span>
<span class="line" id="L221"></span>
<span class="line" id="L222"> <span class="tok-kw">while</span> (data_index &lt; data_end) : (data_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L223"> <span class="tok-kw">const</span> r = <span class="tok-kw">try</span> parseNumber(reader, read_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L224"> <span class="tok-kw">const</span> g = <span class="tok-kw">try</span> parseNumber(reader, read_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L225"> <span class="tok-kw">const</span> b = <span class="tok-kw">try</span> parseNumber(reader, read_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L226"></span>
<span class="line" id="L227"> data[data_index] = color.Rgb24{</span>
<span class="line" id="L228"> .r = <span class="tok-builtin">@truncate</span>(<span class="tok-number">255</span> * r / header.max_value),</span>
<span class="line" id="L229"> .g = <span class="tok-builtin">@truncate</span>(<span class="tok-number">255</span> * g / header.max_value),</span>
<span class="line" id="L230"> .b = <span class="tok-builtin">@truncate</span>(<span class="tok-number">255</span> * b / header.max_value),</span>
<span class="line" id="L231"> };</span>
<span class="line" id="L232"> }</span>
<span class="line" id="L233">}</span>
<span class="line" id="L234"></span>
<span class="line" id="L235"><span class="tok-kw">fn</span> <span class="tok-fn">Netpbm</span>(<span class="tok-kw">comptime</span> image_format: Image.Format, <span class="tok-kw">comptime</span> header_numbers: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L236"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L237"> header: Header = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L238"></span>
<span class="line" id="L239"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L240"></span>
<span class="line" id="L241"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> EncoderOptions = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L242"> binary: <span class="tok-type">bool</span> = <span class="tok-null">true</span>,</span>
<span class="line" id="L243"> };</span>
<span class="line" id="L244"></span>
<span class="line" id="L245"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatInterface</span>() FormatInterface {</span>
<span class="line" id="L246"> <span class="tok-kw">return</span> FormatInterface{</span>
<span class="line" id="L247"> .format = format,</span>
<span class="line" id="L248"> .formatDetect = formatDetect,</span>
<span class="line" id="L249"> .readImage = readImage,</span>
<span class="line" id="L250"> .writeImage = writeImage,</span>
<span class="line" id="L251"> };</span>
<span class="line" id="L252"> }</span>
<span class="line" id="L253"></span>
<span class="line" id="L254"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">format</span>() Image.Format {</span>
<span class="line" id="L255"> <span class="tok-kw">return</span> image_format;</span>
<span class="line" id="L256"> }</span>
<span class="line" id="L257"></span>
<span class="line" id="L258"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatDetect</span>(stream: *Image.Stream) ImageReadError!<span class="tok-type">bool</span> {</span>
<span class="line" id="L259"> <span class="tok-kw">var</span> magic_number_buffer: [<span class="tok-number">2</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L260"> _ = <span class="tok-kw">try</span> stream.read(magic_number_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L261"></span>
<span class="line" id="L262"> <span class="tok-kw">if</span> (magic_number_buffer[<span class="tok-number">0</span>] != <span class="tok-str">'P'</span>) {</span>
<span class="line" id="L263"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L264"> }</span>
<span class="line" id="L265"></span>
<span class="line" id="L266"> <span class="tok-kw">var</span> found = <span class="tok-null">false</span>;</span>
<span class="line" id="L267"></span>
<span class="line" id="L268"> <span class="tok-kw">for</span> (header_numbers) |number| {</span>
<span class="line" id="L269"> <span class="tok-kw">if</span> (magic_number_buffer[<span class="tok-number">1</span>] == number) {</span>
<span class="line" id="L270"> found = <span class="tok-null">true</span>;</span>
<span class="line" id="L271"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L272"> }</span>
<span class="line" id="L273"> }</span>
<span class="line" id="L274"></span>
<span class="line" id="L275"> <span class="tok-kw">return</span> found;</span>
<span class="line" id="L276"> }</span>
<span class="line" id="L277"></span>
<span class="line" id="L278"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readImage</span>(allocator: Allocator, stream: *Image.Stream) ImageReadError!Image {</span>
<span class="line" id="L279"> <span class="tok-kw">var</span> result = Image.init(allocator);</span>
<span class="line" id="L280"> <span class="tok-kw">errdefer</span> result.deinit();</span>
<span class="line" id="L281"> <span class="tok-kw">var</span> netpbm_file = Self{};</span>
<span class="line" id="L282"></span>
<span class="line" id="L283"> <span class="tok-kw">const</span> pixels = <span class="tok-kw">try</span> netpbm_file.read(allocator, stream);</span>
<span class="line" id="L284"></span>
<span class="line" id="L285"> result.width = netpbm_file.header.width;</span>
<span class="line" id="L286"> result.height = netpbm_file.header.height;</span>
<span class="line" id="L287"> result.pixels = pixels;</span>
<span class="line" id="L288"></span>
<span class="line" id="L289"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L290"> }</span>
<span class="line" id="L291"></span>
<span class="line" id="L292"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(allocator: Allocator, write_stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L293"> _ = allocator;</span>
<span class="line" id="L294"></span>
<span class="line" id="L295"> <span class="tok-kw">var</span> netpbm_file = Self{};</span>
<span class="line" id="L296"> netpbm_file.header.binary = <span class="tok-kw">switch</span> (encoder_options) {</span>
<span class="line" id="L297"> .pbm =&gt; |options| options.binary,</span>
<span class="line" id="L298"> .pgm =&gt; |options| options.binary,</span>
<span class="line" id="L299"> .ppm =&gt; |options| options.binary,</span>
<span class="line" id="L300"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">false</span>,</span>
<span class="line" id="L301"> };</span>
<span class="line" id="L302"></span>
<span class="line" id="L303"> netpbm_file.header.width = image.width;</span>
<span class="line" id="L304"> netpbm_file.header.height = image.height;</span>
<span class="line" id="L305"> netpbm_file.header.format = <span class="tok-kw">switch</span> (image.pixels) {</span>
<span class="line" id="L306"> .grayscale1 =&gt; Format.bitmap,</span>
<span class="line" id="L307"> .grayscale8, .grayscale16 =&gt; Format.grayscale,</span>
<span class="line" id="L308"> .rgb24 =&gt; Format.rgb,</span>
<span class="line" id="L309"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L310"> };</span>
<span class="line" id="L311"></span>
<span class="line" id="L312"> netpbm_file.header.max_value = <span class="tok-kw">switch</span> (image.pixels) {</span>
<span class="line" id="L313"> .grayscale16 =&gt; std.math.maxInt(<span class="tok-type">u16</span>),</span>
<span class="line" id="L314"> .grayscale1 =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L315"> <span class="tok-kw">else</span> =&gt; std.math.maxInt(<span class="tok-type">u8</span>),</span>
<span class="line" id="L316"> };</span>
<span class="line" id="L317"></span>
<span class="line" id="L318"> <span class="tok-kw">try</span> netpbm_file.write(write_stream, image.pixels);</span>
<span class="line" id="L319"> }</span>
<span class="line" id="L320"></span>
<span class="line" id="L321"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pixelFormat</span>(self: Self) ImageReadError!PixelFormat {</span>
<span class="line" id="L322"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.header.format) {</span>
<span class="line" id="L323"> .bitmap =&gt; PixelFormat.grayscale1,</span>
<span class="line" id="L324"> .grayscale =&gt; <span class="tok-kw">switch</span> (self.header.max_value) {</span>
<span class="line" id="L325"> <span class="tok-number">0</span>...<span class="tok-number">255</span> =&gt; PixelFormat.grayscale8,</span>
<span class="line" id="L326"> <span class="tok-kw">else</span> =&gt; PixelFormat.grayscale16,</span>
<span class="line" id="L327"> },</span>
<span class="line" id="L328"> .rgb =&gt; PixelFormat.rgb24,</span>
<span class="line" id="L329"> };</span>
<span class="line" id="L330"> }</span>
<span class="line" id="L331"></span>
<span class="line" id="L332"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(self: *Self, allocator: Allocator, stream: *Image.Stream) ImageReadError!color.PixelStorage {</span>
<span class="line" id="L333"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceReader(stream);</span>
<span class="line" id="L334"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L335"> self.header = <span class="tok-kw">try</span> parseHeader(reader);</span>
<span class="line" id="L336"></span>
<span class="line" id="L337"> <span class="tok-kw">const</span> pixel_format = <span class="tok-kw">try</span> self.pixelFormat();</span>
<span class="line" id="L338"></span>
<span class="line" id="L339"> <span class="tok-kw">var</span> pixels = <span class="tok-kw">try</span> color.PixelStorage.init(allocator, pixel_format, self.header.width * self.header.height);</span>
<span class="line" id="L340"> <span class="tok-kw">errdefer</span> pixels.deinit(allocator);</span>
<span class="line" id="L341"></span>
<span class="line" id="L342"> <span class="tok-kw">switch</span> (self.header.format) {</span>
<span class="line" id="L343"> .bitmap =&gt; {</span>
<span class="line" id="L344"> <span class="tok-kw">if</span> (self.header.binary) {</span>
<span class="line" id="L345"> <span class="tok-kw">try</span> loadBinaryBitmap(self.header, pixels.grayscale1, reader);</span>
<span class="line" id="L346"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L347"> <span class="tok-kw">try</span> loadAsciiBitmap(self.header, pixels.grayscale1, reader);</span>
<span class="line" id="L348"> }</span>
<span class="line" id="L349"> },</span>
<span class="line" id="L350"> .grayscale =&gt; {</span>
<span class="line" id="L351"> <span class="tok-kw">if</span> (self.header.binary) {</span>
<span class="line" id="L352"> <span class="tok-kw">try</span> loadBinaryGraymap(self.header, &amp;pixels, reader);</span>
<span class="line" id="L353"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L354"> <span class="tok-kw">try</span> loadAsciiGraymap(self.header, &amp;pixels, reader);</span>
<span class="line" id="L355"> }</span>
<span class="line" id="L356"> },</span>
<span class="line" id="L357"> .rgb =&gt; {</span>
<span class="line" id="L358"> <span class="tok-kw">if</span> (self.header.binary) {</span>
<span class="line" id="L359"> <span class="tok-kw">try</span> loadBinaryRgbmap(self.header, pixels.rgb24, reader);</span>
<span class="line" id="L360"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L361"> <span class="tok-kw">try</span> loadAsciiRgbmap(self.header, pixels.rgb24, reader);</span>
<span class="line" id="L362"> }</span>
<span class="line" id="L363"> },</span>
<span class="line" id="L364"> }</span>
<span class="line" id="L365"></span>
<span class="line" id="L366"> <span class="tok-kw">return</span> pixels;</span>
<span class="line" id="L367"> }</span>
<span class="line" id="L368"></span>
<span class="line" id="L369"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: *Self, write_stream: *Image.Stream, pixels: color.PixelStorage) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L370"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceWriter(write_stream);</span>
<span class="line" id="L371"></span>
<span class="line" id="L372"> <span class="tok-kw">const</span> image_type = <span class="tok-kw">if</span> (self.header.binary) header_numbers[<span class="tok-number">1</span>] <span class="tok-kw">else</span> header_numbers[<span class="tok-number">0</span>];</span>
<span class="line" id="L373"> <span class="tok-kw">const</span> writer = buffered_stream.writer();</span>
<span class="line" id="L374"> <span class="tok-kw">try</span> writer.print(<span class="tok-str">&quot;P{c}\n&quot;</span>, .{image_type});</span>
<span class="line" id="L375"> _ = <span class="tok-kw">try</span> writer.write(<span class="tok-str">&quot;# Created by zigimg\n&quot;</span>);</span>
<span class="line" id="L376"></span>
<span class="line" id="L377"> <span class="tok-kw">try</span> writer.print(<span class="tok-str">&quot;{} {}\n&quot;</span>, .{ self.header.width, self.header.height });</span>
<span class="line" id="L378"></span>
<span class="line" id="L379"> <span class="tok-kw">if</span> (self.header.format != .bitmap) {</span>
<span class="line" id="L380"> <span class="tok-kw">try</span> writer.print(<span class="tok-str">&quot;{}\n&quot;</span>, .{self.header.max_value});</span>
<span class="line" id="L381"> }</span>
<span class="line" id="L382"></span>
<span class="line" id="L383"> <span class="tok-kw">if</span> (self.header.binary) {</span>
<span class="line" id="L384"> <span class="tok-kw">switch</span> (self.header.format) {</span>
<span class="line" id="L385"> .bitmap =&gt; {</span>
<span class="line" id="L386"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L387"> .grayscale1 =&gt; |samples| {</span>
<span class="line" id="L388"> <span class="tok-kw">var</span> bit_writer = std.io.bitWriter(.big, writer);</span>
<span class="line" id="L389"></span>
<span class="line" id="L390"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..self.header.height) |row_index| {</span>
<span class="line" id="L391"> <span class="tok-kw">for</span> (samples[row_index * self.header.width ..][<span class="tok-number">0</span>..self.header.width]) |sample| {</span>
<span class="line" id="L392"> <span class="tok-kw">try</span> bit_writer.writeBits(~sample.value, <span class="tok-number">1</span>);</span>
<span class="line" id="L393"> }</span>
<span class="line" id="L394"> <span class="tok-kw">try</span> bit_writer.flushBits();</span>
<span class="line" id="L395"> }</span>
<span class="line" id="L396"> },</span>
<span class="line" id="L397"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L398"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L399"> },</span>
<span class="line" id="L400"> }</span>
<span class="line" id="L401"> },</span>
<span class="line" id="L402"> .grayscale =&gt; {</span>
<span class="line" id="L403"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L404"> .grayscale16 =&gt; {</span>
<span class="line" id="L405"> <span class="tok-kw">for</span> (pixels.grayscale16) |entry| {</span>
<span class="line" id="L406"> <span class="tok-comment">// Big due to 16-bit PGM being semi standardized as big-endian</span>
</span>
<span class="line" id="L407"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, entry.value, .big);</span>
<span class="line" id="L408"> }</span>
<span class="line" id="L409"> },</span>
<span class="line" id="L410"> .grayscale8 =&gt; {</span>
<span class="line" id="L411"> <span class="tok-kw">for</span> (pixels.grayscale8) |entry| {</span>
<span class="line" id="L412"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u8</span>, entry.value, .little);</span>
<span class="line" id="L413"> }</span>
<span class="line" id="L414"> },</span>
<span class="line" id="L415"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L416"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L417"> },</span>
<span class="line" id="L418"> }</span>
<span class="line" id="L419"> },</span>
<span class="line" id="L420"> .rgb =&gt; {</span>
<span class="line" id="L421"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L422"> .rgb24 =&gt; {</span>
<span class="line" id="L423"> <span class="tok-kw">for</span> (pixels.rgb24) |entry| {</span>
<span class="line" id="L424"> <span class="tok-kw">try</span> writer.writeByte(entry.r);</span>
<span class="line" id="L425"> <span class="tok-kw">try</span> writer.writeByte(entry.g);</span>
<span class="line" id="L426"> <span class="tok-kw">try</span> writer.writeByte(entry.b);</span>
<span class="line" id="L427"> }</span>
<span class="line" id="L428"> },</span>
<span class="line" id="L429"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L430"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L431"> },</span>
<span class="line" id="L432"> }</span>
<span class="line" id="L433"> },</span>
<span class="line" id="L434"> }</span>
<span class="line" id="L435"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L436"> <span class="tok-kw">switch</span> (self.header.format) {</span>
<span class="line" id="L437"> .bitmap =&gt; {</span>
<span class="line" id="L438"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L439"> .grayscale1 =&gt; {</span>
<span class="line" id="L440"> <span class="tok-kw">for</span> (pixels.grayscale1) |entry| {</span>
<span class="line" id="L441"> <span class="tok-kw">try</span> writer.print(<span class="tok-str">&quot;{}&quot;</span>, .{~entry.value});</span>
<span class="line" id="L442"> }</span>
<span class="line" id="L443"> _ = <span class="tok-kw">try</span> writer.write(<span class="tok-str">&quot;\n&quot;</span>);</span>
<span class="line" id="L444"> },</span>
<span class="line" id="L445"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L446"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L447"> },</span>
<span class="line" id="L448"> }</span>
<span class="line" id="L449"> },</span>
<span class="line" id="L450"> .grayscale =&gt; {</span>
<span class="line" id="L451"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L452"> .grayscale16 =&gt; {</span>
<span class="line" id="L453"> <span class="tok-kw">const</span> pixels_len = pixels.len();</span>
<span class="line" id="L454"> <span class="tok-kw">for</span> (pixels.grayscale16, <span class="tok-number">0</span>..) |entry, index| {</span>
<span class="line" id="L455"> <span class="tok-kw">try</span> writer.print(<span class="tok-str">&quot;{}&quot;</span>, .{entry.value});</span>
<span class="line" id="L456"></span>
<span class="line" id="L457"> <span class="tok-kw">if</span> (index != (pixels_len - <span class="tok-number">1</span>)) {</span>
<span class="line" id="L458"> _ = <span class="tok-kw">try</span> writer.write(<span class="tok-str">&quot; &quot;</span>);</span>
<span class="line" id="L459"> }</span>
<span class="line" id="L460"> }</span>
<span class="line" id="L461"> _ = <span class="tok-kw">try</span> writer.write(<span class="tok-str">&quot;\n&quot;</span>);</span>
<span class="line" id="L462"> },</span>
<span class="line" id="L463"> .grayscale8 =&gt; {</span>
<span class="line" id="L464"> <span class="tok-kw">const</span> pixels_len = pixels.len();</span>
<span class="line" id="L465"> <span class="tok-kw">for</span> (pixels.grayscale8, <span class="tok-number">0</span>..) |entry, index| {</span>
<span class="line" id="L466"> <span class="tok-kw">try</span> writer.print(<span class="tok-str">&quot;{}&quot;</span>, .{entry.value});</span>
<span class="line" id="L467"></span>
<span class="line" id="L468"> <span class="tok-kw">if</span> (index != (pixels_len - <span class="tok-number">1</span>)) {</span>
<span class="line" id="L469"> _ = <span class="tok-kw">try</span> writer.write(<span class="tok-str">&quot; &quot;</span>);</span>
<span class="line" id="L470"> }</span>
<span class="line" id="L471"> }</span>
<span class="line" id="L472"> _ = <span class="tok-kw">try</span> writer.write(<span class="tok-str">&quot;\n&quot;</span>);</span>
<span class="line" id="L473"> },</span>
<span class="line" id="L474"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L475"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L476"> },</span>
<span class="line" id="L477"> }</span>
<span class="line" id="L478"> },</span>
<span class="line" id="L479"> .rgb =&gt; {</span>
<span class="line" id="L480"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L481"> .rgb24 =&gt; {</span>
<span class="line" id="L482"> <span class="tok-kw">for</span> (pixels.rgb24) |entry| {</span>
<span class="line" id="L483"> <span class="tok-kw">try</span> writer.print(<span class="tok-str">&quot;{} {} {}\n&quot;</span>, .{ entry.r, entry.g, entry.b });</span>
<span class="line" id="L484"> }</span>
<span class="line" id="L485"> },</span>
<span class="line" id="L486"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L487"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L488"> },</span>
<span class="line" id="L489"> }</span>
<span class="line" id="L490"> },</span>
<span class="line" id="L491"> }</span>
<span class="line" id="L492"> }</span>
<span class="line" id="L493"></span>
<span class="line" id="L494"> <span class="tok-kw">try</span> buffered_stream.flush();</span>
<span class="line" id="L495"> }</span>
<span class="line" id="L496"> };</span>
<span class="line" id="L497">}</span>
<span class="line" id="L498"></span>
<span class="line" id="L499"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PBM = Netpbm(Image.Format.pbm, &amp;[_]<span class="tok-type">u8</span>{ <span class="tok-str">'1'</span>, <span class="tok-str">'4'</span> });</span>
<span class="line" id="L500"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PGM = Netpbm(Image.Format.pgm, &amp;[_]<span class="tok-type">u8</span>{ <span class="tok-str">'2'</span>, <span class="tok-str">'5'</span> });</span>
<span class="line" id="L501"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PPM = Netpbm(Image.Format.ppm, &amp;[_]<span class="tok-type">u8</span>{ <span class="tok-str">'3'</span>, <span class="tok-str">'6'</span> });</span>
<span class="line" id="L502"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,694 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/pam.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> io = std.io;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> mem = std.mem;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> math = std.math;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> ascii = std.ascii;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> fmt = std.fmt;</span>
<span class="line" id="L7"><span class="tok-kw">const</span> meta = std.meta;</span>
<span class="line" id="L8"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../color.zig&quot;</span>);</span>
<span class="line" id="L11"><span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L12"><span class="tok-kw">const</span> PixelStorage = color.PixelStorage;</span>
<span class="line" id="L13"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L14"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>);</span>
<span class="line" id="L15"><span class="tok-kw">const</span> ImageError = Image.Error;</span>
<span class="line" id="L16"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L17"><span class="tok-kw">const</span> ImageWriteError = Image.WriteError;</span>
<span class="line" id="L18"><span class="tok-kw">const</span> utils = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../utils.zig&quot;</span>);</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-comment">/// Represents all supported values for `TUPLTYPE`.</span></span>
<span class="line" id="L21"><span class="tok-kw">const</span> TupleType = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L22"> mono,</span>
<span class="line" id="L23"> mono_a,</span>
<span class="line" id="L24"> gray,</span>
<span class="line" id="L25"> gray_a,</span>
<span class="line" id="L26"> rgb,</span>
<span class="line" id="L27"> rgb_a,</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"> <span class="tok-comment">/// Returns the `TupleType` corresponding to `string`, or</span></span>
<span class="line" id="L30"> <span class="tok-comment">/// `error.Unsupported` if it is unknown.</span></span>
<span class="line" id="L31"> <span class="tok-kw">fn</span> <span class="tok-fn">fromString</span>(string: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-kw">error</span>{Unsupported}!TupleType {</span>
<span class="line" id="L32"> <span class="tok-comment">// zig fmt: off</span>
</span>
<span class="line" id="L33"> <span class="tok-kw">return</span> <span class="tok-kw">if</span>(mem.eql(<span class="tok-type">u8</span>, string, <span class="tok-str">&quot;BLACKANDWHITE&quot;</span>)) .mono</span>
<span class="line" id="L34"> <span class="tok-kw">else</span> <span class="tok-kw">if</span>(mem.eql(<span class="tok-type">u8</span>, string, <span class="tok-str">&quot;BLACKANDWHITE_ALPHA&quot;</span>)) .mono_a</span>
<span class="line" id="L35"> <span class="tok-kw">else</span> <span class="tok-kw">if</span>(mem.eql(<span class="tok-type">u8</span>, string, <span class="tok-str">&quot;GRAYSCALE&quot;</span>)) .gray</span>
<span class="line" id="L36"> <span class="tok-kw">else</span> <span class="tok-kw">if</span>(mem.eql(<span class="tok-type">u8</span>, string, <span class="tok-str">&quot;GRAYSCALE_ALPHA&quot;</span>)) .gray_a</span>
<span class="line" id="L37"> <span class="tok-kw">else</span> <span class="tok-kw">if</span>(mem.eql(<span class="tok-type">u8</span>, string, <span class="tok-str">&quot;RGB&quot;</span>)) .rgb</span>
<span class="line" id="L38"> <span class="tok-kw">else</span> <span class="tok-kw">if</span>(mem.eql(<span class="tok-type">u8</span>, string, <span class="tok-str">&quot;RGB_ALPHA&quot;</span>)) .rgb_a</span>
<span class="line" id="L39"> <span class="tok-kw">else</span> <span class="tok-kw">error</span>.Unsupported; <span class="tok-comment">// Unknown tuple type</span>
</span>
<span class="line" id="L40"> <span class="tok-comment">// zig fmt: on</span>
</span>
<span class="line" id="L41"> }</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"> <span class="tok-comment">/// Returns the `TUPLTYPE` string representation of `tuple_type`.</span></span>
<span class="line" id="L44"> <span class="tok-kw">fn</span> <span class="tok-fn">toString</span>(tuple_type: TupleType) []<span class="tok-kw">const</span> <span class="tok-type">u8</span> {</span>
<span class="line" id="L45"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (tuple_type) {</span>
<span class="line" id="L46"> .mono =&gt; <span class="tok-str">&quot;BLACKANDWHITE&quot;</span>,</span>
<span class="line" id="L47"> .mono_a =&gt; <span class="tok-str">&quot;BLACKANDWHITE_ALPHA&quot;</span>,</span>
<span class="line" id="L48"> .gray =&gt; <span class="tok-str">&quot;GRAYSCALE&quot;</span>,</span>
<span class="line" id="L49"> .gray_a =&gt; <span class="tok-str">&quot;GRAYSCALE_ALPHA&quot;</span>,</span>
<span class="line" id="L50"> .rgb =&gt; <span class="tok-str">&quot;RGB&quot;</span>,</span>
<span class="line" id="L51"> .rgb_a =&gt; <span class="tok-str">&quot;RGB_ALPHA&quot;</span>,</span>
<span class="line" id="L52"> };</span>
<span class="line" id="L53"> }</span>
<span class="line" id="L54">};</span>
<span class="line" id="L55"></span>
<span class="line" id="L56"><span class="tok-comment">/// Represents a PAM header.</span></span>
<span class="line" id="L57"><span class="tok-kw">const</span> Header = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L58"> <span class="tok-comment">/// Number of pixels in a row.</span></span>
<span class="line" id="L59"> width: <span class="tok-type">usize</span>,</span>
<span class="line" id="L60"> <span class="tok-comment">/// Number of rows.</span></span>
<span class="line" id="L61"> height: <span class="tok-type">usize</span>,</span>
<span class="line" id="L62"> <span class="tok-comment">/// Number of components per pixels.</span></span>
<span class="line" id="L63"> depth: <span class="tok-type">usize</span>,</span>
<span class="line" id="L64"> <span class="tok-comment">/// Maximum value of a component.</span></span>
<span class="line" id="L65"> maxval: <span class="tok-type">u16</span>,</span>
<span class="line" id="L66"> <span class="tok-comment">/// Tuple type of the image.</span></span>
<span class="line" id="L67"> tuple_type: TupleType,</span>
<span class="line" id="L68"> <span class="tok-comment">/// Arbitrary text comments. Note that comment position inside the</span></span>
<span class="line" id="L69"> <span class="tok-comment">/// header is not preserved.</span></span>
<span class="line" id="L70"> comments: []<span class="tok-kw">const</span> []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L71"></span>
<span class="line" id="L72"> <span class="tok-comment">/// Reads a header from `reader`, using `allocator` to allocate</span></span>
<span class="line" id="L73"> <span class="tok-comment">/// memory. Returns that header, `error.Unsupported` if the tuple</span></span>
<span class="line" id="L74"> <span class="tok-comment">/// type is not known to us, `error.OutOfMemory` if allocation</span></span>
<span class="line" id="L75"> <span class="tok-comment">/// fails, `error.InvalidData` if the header does not conform to</span></span>
<span class="line" id="L76"> <span class="tok-comment">/// the PAM specification, or another error specific to `reader`</span></span>
<span class="line" id="L77"> <span class="tok-comment">/// if reading fails.</span></span>
<span class="line" id="L78"> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(allocator: Allocator, reader: <span class="tok-kw">anytype</span>) (<span class="tok-kw">error</span>{ InvalidData, Unsupported, OutOfMemory, EndOfStream, StreamTooLong } || <span class="tok-builtin">@TypeOf</span>(reader).Error)!Header {</span>
<span class="line" id="L79"> <span class="tok-kw">var</span> maybe_width: ?<span class="tok-type">usize</span> = <span class="tok-null">null</span>;</span>
<span class="line" id="L80"> <span class="tok-kw">var</span> maybe_height: ?<span class="tok-type">usize</span> = <span class="tok-null">null</span>;</span>
<span class="line" id="L81"> <span class="tok-kw">var</span> maybe_depth: ?<span class="tok-type">usize</span> = <span class="tok-null">null</span>;</span>
<span class="line" id="L82"> <span class="tok-kw">var</span> maybe_maxval: ?<span class="tok-type">u16</span> = <span class="tok-null">null</span>;</span>
<span class="line" id="L83"> <span class="tok-kw">var</span> maybe_tuple_type: ?TupleType = <span class="tok-null">null</span>;</span>
<span class="line" id="L84"> <span class="tok-kw">var</span> comments = std.ArrayListUnmanaged([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>){};</span>
<span class="line" id="L85"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L86"> <span class="tok-kw">for</span> (comments.items) |comment| allocator.free(comment);</span>
<span class="line" id="L87"> comments.deinit(allocator);</span>
<span class="line" id="L88"> }</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> {</span>
<span class="line" id="L91"> <span class="tok-kw">var</span> buf = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u8</span>).initCapacity(allocator, <span class="tok-number">32</span>);</span>
<span class="line" id="L92"> <span class="tok-kw">defer</span> buf.deinit();</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L95"> <span class="tok-comment">// we fail on EOS here because a valid pam header must end with ENDHDR</span>
</span>
<span class="line" id="L96"> <span class="tok-kw">try</span> reader.readUntilDelimiterArrayList(&amp;buf, <span class="tok-str">'\n'</span>, math.maxInt(<span class="tok-type">usize</span>));</span>
<span class="line" id="L97"> <span class="tok-kw">const</span> line = buf.items; <span class="tok-comment">// empty lines are meaningless</span>
</span>
<span class="line" id="L98"> <span class="tok-kw">if</span> (line.len == <span class="tok-number">0</span>) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L99"> <span class="tok-kw">if</span> (line[<span class="tok-number">0</span>] == <span class="tok-str">'#'</span>) { <span class="tok-comment">// comment</span>
</span>
<span class="line" id="L100"> <span class="tok-kw">try</span> comments.append(allocator, <span class="tok-kw">try</span> allocator.dupe(<span class="tok-type">u8</span>, line[<span class="tok-number">1</span>..]));</span>
<span class="line" id="L101"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103"></span>
<span class="line" id="L104"> <span class="tok-kw">var</span> tok_iter = mem.tokenize(<span class="tok-type">u8</span>, line, &amp;ascii.whitespace);</span>
<span class="line" id="L105"> <span class="tok-kw">const</span> first_token = tok_iter.next() <span class="tok-kw">orelse</span> <span class="tok-kw">continue</span>; <span class="tok-comment">// lines with 0 tokens are meaningless</span>
</span>
<span class="line" id="L106"></span>
<span class="line" id="L107"> <span class="tok-kw">if</span> (first_token.len &gt; <span class="tok-number">8</span>) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// the first token must be at most 8 bytes</span>
</span>
<span class="line" id="L108"></span>
<span class="line" id="L109"> <span class="tok-kw">if</span> (mem.eql(<span class="tok-type">u8</span>, first_token, <span class="tok-str">&quot;ENDHDR&quot;</span>)) <span class="tok-kw">break</span>;</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"> <span class="tok-kw">if</span> (mem.eql(<span class="tok-type">u8</span>, first_token, <span class="tok-str">&quot;TUPLTYPE&quot;</span>)) {</span>
<span class="line" id="L112"> maybe_tuple_type = <span class="tok-kw">try</span> TupleType.fromString(tok_iter.rest());</span>
<span class="line" id="L113"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L114"> }</span>
<span class="line" id="L115"></span>
<span class="line" id="L116"> <span class="tok-kw">const</span> second_token = tok_iter.next() <span class="tok-kw">orelse</span> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// bad token</span>
</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"> <span class="tok-kw">if</span> (mem.eql(<span class="tok-type">u8</span>, first_token, <span class="tok-str">&quot;WIDTH&quot;</span>)) {</span>
<span class="line" id="L119"> maybe_width = fmt.parseUnsigned(<span class="tok-type">usize</span>, second_token, <span class="tok-number">10</span>) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// bad width</span>
</span>
<span class="line" id="L120"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (mem.eql(<span class="tok-type">u8</span>, first_token, <span class="tok-str">&quot;HEIGHT&quot;</span>)) {</span>
<span class="line" id="L121"> maybe_height = fmt.parseUnsigned(<span class="tok-type">usize</span>, second_token, <span class="tok-number">10</span>) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// bad height</span>
</span>
<span class="line" id="L122"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (mem.eql(<span class="tok-type">u8</span>, first_token, <span class="tok-str">&quot;DEPTH&quot;</span>)) {</span>
<span class="line" id="L123"> maybe_depth = fmt.parseUnsigned(<span class="tok-type">usize</span>, second_token, <span class="tok-number">10</span>) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// bad depth</span>
</span>
<span class="line" id="L124"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (mem.eql(<span class="tok-type">u8</span>, first_token, <span class="tok-str">&quot;MAXVAL&quot;</span>)) {</span>
<span class="line" id="L125"> maybe_maxval = fmt.parseUnsigned(<span class="tok-type">u16</span>, second_token, <span class="tok-number">10</span>) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// bad maxval</span>
</span>
<span class="line" id="L126"> } <span class="tok-kw">else</span> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// invalid first token</span>
</span>
<span class="line" id="L127"> }</span>
<span class="line" id="L128"> }</span>
<span class="line" id="L129"></span>
<span class="line" id="L130"> <span class="tok-kw">if</span> (maybe_height == <span class="tok-null">null</span> <span class="tok-kw">or</span> maybe_width == <span class="tok-null">null</span> <span class="tok-kw">or</span> maybe_maxval == <span class="tok-null">null</span> <span class="tok-kw">or</span> maybe_depth == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// missing values</span>
</span>
<span class="line" id="L131"> <span class="tok-kw">if</span> (maybe_height.? &lt; <span class="tok-number">1</span> <span class="tok-kw">or</span> maybe_width.? &lt; <span class="tok-number">1</span> <span class="tok-kw">or</span> maybe_maxval.? &lt; <span class="tok-number">1</span>) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// bad width, height, or maxval</span>
</span>
<span class="line" id="L132"> <span class="tok-kw">if</span> (maybe_tuple_type == <span class="tok-null">null</span>) { <span class="tok-comment">// guess tuple type</span>
</span>
<span class="line" id="L133"> <span class="tok-kw">const</span> depth = maybe_depth.?;</span>
<span class="line" id="L134"> <span class="tok-kw">const</span> maxval = maybe_maxval.?;</span>
<span class="line" id="L135"> maybe_tuple_type = <span class="tok-kw">switch</span> (depth) {</span>
<span class="line" id="L136"> <span class="tok-number">1</span> =&gt; <span class="tok-kw">if</span> (maxval == <span class="tok-number">1</span>) TupleType.mono <span class="tok-kw">else</span> TupleType.gray,</span>
<span class="line" id="L137"> <span class="tok-number">2</span> =&gt; <span class="tok-kw">if</span> (maxval == <span class="tok-number">1</span>) TupleType.mono_a <span class="tok-kw">else</span> TupleType.gray_a,</span>
<span class="line" id="L138"> <span class="tok-number">3</span> =&gt; TupleType.rgb,</span>
<span class="line" id="L139"> <span class="tok-number">4</span> =&gt; TupleType.rgb_a,</span>
<span class="line" id="L140"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unsupported, <span class="tok-comment">// can't guess tuple type</span>
</span>
<span class="line" id="L141"> };</span>
<span class="line" id="L142"> }</span>
<span class="line" id="L143"></span>
<span class="line" id="L144"> <span class="tok-kw">const</span> tuple_type_matches = <span class="tok-kw">if</span> (maybe_depth) |depth| <span class="tok-kw">if</span> (maybe_maxval) |maxval| <span class="tok-kw">switch</span> (maybe_tuple_type.?) {</span>
<span class="line" id="L145"> .mono =&gt; depth == <span class="tok-number">1</span> <span class="tok-kw">and</span> maxval == <span class="tok-number">1</span>,</span>
<span class="line" id="L146"> .mono_a =&gt; depth == <span class="tok-number">2</span> <span class="tok-kw">and</span> maxval == <span class="tok-number">1</span>,</span>
<span class="line" id="L147"> .gray =&gt; depth == <span class="tok-number">1</span>,</span>
<span class="line" id="L148"> .gray_a =&gt; depth == <span class="tok-number">2</span>,</span>
<span class="line" id="L149"> .rgb =&gt; depth == <span class="tok-number">3</span>,</span>
<span class="line" id="L150"> .rgb_a =&gt; depth == <span class="tok-number">4</span>,</span>
<span class="line" id="L151"> } <span class="tok-kw">else</span> <span class="tok-kw">unreachable</span> <span class="tok-kw">else</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L152"></span>
<span class="line" id="L153"> <span class="tok-kw">if</span> (!tuple_type_matches) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// tuple type does not match</span>
</span>
<span class="line" id="L154"></span>
<span class="line" id="L155"> <span class="tok-kw">return</span> Header{</span>
<span class="line" id="L156"> .width = maybe_width.?,</span>
<span class="line" id="L157"> .height = maybe_height.?,</span>
<span class="line" id="L158"> .maxval = maybe_maxval.?,</span>
<span class="line" id="L159"> .depth = maybe_depth.?,</span>
<span class="line" id="L160"> .tuple_type = maybe_tuple_type.?,</span>
<span class="line" id="L161"> .comments = <span class="tok-kw">try</span> comments.toOwnedSlice(allocator),</span>
<span class="line" id="L162"> };</span>
<span class="line" id="L163"> }</span>
<span class="line" id="L164"></span>
<span class="line" id="L165"> <span class="tok-comment">/// Writes the PAM representation of `header` to `writer`. If</span></span>
<span class="line" id="L166"> <span class="tok-comment">/// writing fails, returns an error specific to `writer`.</span></span>
<span class="line" id="L167"> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(header: Header, writer: <span class="tok-kw">anytype</span>) <span class="tok-builtin">@TypeOf</span>(writer).Error!<span class="tok-type">void</span> {</span>
<span class="line" id="L168"> <span class="tok-kw">try</span> writer.writeAll(<span class="tok-str">&quot;P7\n&quot;</span>);</span>
<span class="line" id="L169"></span>
<span class="line" id="L170"> <span class="tok-kw">for</span> (header.comments) |comment|</span>
<span class="line" id="L171"> <span class="tok-kw">try</span> writer.print(<span class="tok-str">&quot;#{s}\n&quot;</span>, .{comment});</span>
<span class="line" id="L172"></span>
<span class="line" id="L173"> <span class="tok-kw">const</span> fmtstr =</span>
<span class="line" id="L174"> <span class="tok-str">\\WIDTH {d}</span></span>
<span class="line" id="L175"> <span class="tok-str">\\HEIGHT {d}</span></span>
<span class="line" id="L176"> <span class="tok-str">\\DEPTH {d}</span></span>
<span class="line" id="L177"> <span class="tok-str">\\MAXVAL {d}</span></span>
<span class="line" id="L178"> <span class="tok-str">\\TUPLTYPE {s}</span></span>
<span class="line" id="L179"> <span class="tok-str">\\ENDHDR</span></span>
<span class="line" id="L180"> <span class="tok-str">\\</span></span>
<span class="line" id="L181"> ;</span>
<span class="line" id="L182"> <span class="tok-kw">try</span> writer.print(fmtstr, .{ header.width, header.height, header.depth, header.maxval, header.tuple_type.toString() });</span>
<span class="line" id="L183"> }</span>
<span class="line" id="L184"></span>
<span class="line" id="L185"> <span class="tok-comment">/// Invalidates `header` and frees all comments with `allocator`.</span></span>
<span class="line" id="L186"> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(header: *Header, allocator: Allocator) <span class="tok-type">void</span> {</span>
<span class="line" id="L187"> <span class="tok-kw">for</span> (header.comments) |comment| {</span>
<span class="line" id="L188"> allocator.free(comment);</span>
<span class="line" id="L189"> }</span>
<span class="line" id="L190"> allocator.free(header.comments);</span>
<span class="line" id="L191"> header.* = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L192"> }</span>
<span class="line" id="L193"></span>
<span class="line" id="L194"> <span class="tok-kw">fn</span> <span class="tok-fn">hasTwoBytesPerComponent</span>(header: Header) <span class="tok-type">bool</span> {</span>
<span class="line" id="L195"> <span class="tok-kw">return</span> header.maxval &gt; math.maxInt(<span class="tok-type">u8</span>);</span>
<span class="line" id="L196"> }</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-kw">fn</span> <span class="tok-fn">getPixelFormat</span>(header: Header) PixelFormat {</span>
<span class="line" id="L199"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (header.tuple_type) {</span>
<span class="line" id="L200"> .mono =&gt; .grayscale1,</span>
<span class="line" id="L201"> <span class="tok-comment">// TODO: is this conversion acceptable?</span>
</span>
<span class="line" id="L202"> .mono_a =&gt; .grayscale1,</span>
<span class="line" id="L203"> .gray =&gt; <span class="tok-kw">if</span> (header.hasTwoBytesPerComponent()) .grayscale16 <span class="tok-kw">else</span> .grayscale8,</span>
<span class="line" id="L204"> .gray_a =&gt; <span class="tok-kw">if</span> (header.hasTwoBytesPerComponent()) .grayscale16Alpha <span class="tok-kw">else</span> .grayscale8Alpha,</span>
<span class="line" id="L205"> .rgb =&gt; <span class="tok-kw">if</span> (header.hasTwoBytesPerComponent()) .rgb48 <span class="tok-kw">else</span> .rgb24,</span>
<span class="line" id="L206"> .rgb_a =&gt; <span class="tok-kw">if</span> (header.hasTwoBytesPerComponent()) .rgba64 <span class="tok-kw">else</span> .rgba32,</span>
<span class="line" id="L207"> };</span>
<span class="line" id="L208"> }</span>
<span class="line" id="L209"></span>
<span class="line" id="L210"> <span class="tok-comment">/// Initializes an `Image` with the values that `header`</span></span>
<span class="line" id="L211"> <span class="tok-comment">/// contains. Returns `error.OutOfMemory` if allocation fails.</span></span>
<span class="line" id="L212"> <span class="tok-kw">fn</span> <span class="tok-fn">initImage</span>(header: Header, allocator: Allocator) <span class="tok-kw">error</span>{OutOfMemory}!Image {</span>
<span class="line" id="L213"> <span class="tok-kw">var</span> image = Image.init(allocator);</span>
<span class="line" id="L214"> image.width = header.width;</span>
<span class="line" id="L215"> image.height = header.height;</span>
<span class="line" id="L216"> image.pixels = <span class="tok-kw">try</span> PixelStorage.init(allocator, header.getPixelFormat(), header.width * header.height);</span>
<span class="line" id="L217"> <span class="tok-kw">return</span> image;</span>
<span class="line" id="L218"> }</span>
<span class="line" id="L219"></span>
<span class="line" id="L220"> <span class="tok-comment">/// Initializes a `Header` from `image`. Returns</span></span>
<span class="line" id="L221"> <span class="tok-comment">/// `error.Unsupported` if the pixel format of `image` cannot be</span></span>
<span class="line" id="L222"> <span class="tok-comment">/// easily represented in PAM.</span></span>
<span class="line" id="L223"> <span class="tok-kw">fn</span> <span class="tok-fn">fromImage</span>(image: Image) <span class="tok-kw">error</span>{Unsupported}!Header {</span>
<span class="line" id="L224"> <span class="tok-kw">var</span> header: Header = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L225"> <span class="tok-kw">switch</span> (image.pixelFormat()) {</span>
<span class="line" id="L226"> .invalid,</span>
<span class="line" id="L227"> .indexed1,</span>
<span class="line" id="L228"> .indexed2,</span>
<span class="line" id="L229"> .indexed4,</span>
<span class="line" id="L230"> .indexed8,</span>
<span class="line" id="L231"> .indexed16,</span>
<span class="line" id="L232"> .float32,</span>
<span class="line" id="L233"> .rgb565,</span>
<span class="line" id="L234"> =&gt; <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unsupported, <span class="tok-comment">// unsupported pixel format</span>
</span>
<span class="line" id="L235"></span>
<span class="line" id="L236"> .grayscale1 =&gt; {</span>
<span class="line" id="L237"> header.depth = <span class="tok-number">1</span>;</span>
<span class="line" id="L238"> header.maxval = <span class="tok-number">1</span>;</span>
<span class="line" id="L239"> header.tuple_type = .mono;</span>
<span class="line" id="L240"> },</span>
<span class="line" id="L241"> .grayscale2 =&gt; {</span>
<span class="line" id="L242"> header.depth = <span class="tok-number">1</span>;</span>
<span class="line" id="L243"> header.maxval = math.maxInt(<span class="tok-type">u2</span>);</span>
<span class="line" id="L244"> header.tuple_type = .gray;</span>
<span class="line" id="L245"> },</span>
<span class="line" id="L246"> .grayscale4 =&gt; {</span>
<span class="line" id="L247"> header.depth = <span class="tok-number">1</span>;</span>
<span class="line" id="L248"> header.maxval = math.maxInt(<span class="tok-type">u4</span>);</span>
<span class="line" id="L249"> header.tuple_type = .gray;</span>
<span class="line" id="L250"> },</span>
<span class="line" id="L251"> .grayscale8 =&gt; {</span>
<span class="line" id="L252"> header.depth = <span class="tok-number">1</span>;</span>
<span class="line" id="L253"> header.maxval = math.maxInt(<span class="tok-type">u8</span>);</span>
<span class="line" id="L254"> header.tuple_type = .gray;</span>
<span class="line" id="L255"> },</span>
<span class="line" id="L256"> .grayscale8Alpha =&gt; {</span>
<span class="line" id="L257"> header.depth = <span class="tok-number">2</span>;</span>
<span class="line" id="L258"> header.maxval = math.maxInt(<span class="tok-type">u8</span>);</span>
<span class="line" id="L259"> header.tuple_type = .gray_a;</span>
<span class="line" id="L260"> },</span>
<span class="line" id="L261"> .grayscale16 =&gt; {</span>
<span class="line" id="L262"> header.depth = <span class="tok-number">1</span>;</span>
<span class="line" id="L263"> header.maxval = math.maxInt(<span class="tok-type">u16</span>);</span>
<span class="line" id="L264"> header.tuple_type = .gray;</span>
<span class="line" id="L265"> },</span>
<span class="line" id="L266"> .grayscale16Alpha =&gt; {</span>
<span class="line" id="L267"> header.depth = <span class="tok-number">2</span>;</span>
<span class="line" id="L268"> header.maxval = math.maxInt(<span class="tok-type">u16</span>);</span>
<span class="line" id="L269"> header.tuple_type = .gray_a;</span>
<span class="line" id="L270"> },</span>
<span class="line" id="L271"> .rgb555, .bgr555 =&gt; {</span>
<span class="line" id="L272"> header.depth = <span class="tok-number">3</span>;</span>
<span class="line" id="L273"> header.maxval = math.maxInt(<span class="tok-type">u5</span>);</span>
<span class="line" id="L274"> header.tuple_type = .rgb;</span>
<span class="line" id="L275"> },</span>
<span class="line" id="L276"> .rgb24, .bgr24 =&gt; {</span>
<span class="line" id="L277"> header.depth = <span class="tok-number">3</span>;</span>
<span class="line" id="L278"> header.maxval = math.maxInt(<span class="tok-type">u8</span>);</span>
<span class="line" id="L279"> header.tuple_type = .rgb;</span>
<span class="line" id="L280"> },</span>
<span class="line" id="L281"> .rgba32, .bgra32 =&gt; {</span>
<span class="line" id="L282"> header.depth = <span class="tok-number">4</span>;</span>
<span class="line" id="L283"> header.maxval = math.maxInt(<span class="tok-type">u8</span>);</span>
<span class="line" id="L284"> header.tuple_type = .rgb_a;</span>
<span class="line" id="L285"> },</span>
<span class="line" id="L286"> .rgb48 =&gt; {</span>
<span class="line" id="L287"> header.depth = <span class="tok-number">3</span>;</span>
<span class="line" id="L288"> header.maxval = math.maxInt(<span class="tok-type">u16</span>);</span>
<span class="line" id="L289"> header.tuple_type = .rgb;</span>
<span class="line" id="L290"> },</span>
<span class="line" id="L291"> .rgba64 =&gt; {</span>
<span class="line" id="L292"> header.depth = <span class="tok-number">4</span>;</span>
<span class="line" id="L293"> header.maxval = math.maxInt(<span class="tok-type">u16</span>);</span>
<span class="line" id="L294"> header.tuple_type = .rgb_a;</span>
<span class="line" id="L295"> },</span>
<span class="line" id="L296"> }</span>
<span class="line" id="L297"> header.comments = &amp;.{};</span>
<span class="line" id="L298"> header.width = image.width;</span>
<span class="line" id="L299"> header.height = image.height;</span>
<span class="line" id="L300"> <span class="tok-kw">return</span> header;</span>
<span class="line" id="L301"> }</span>
<span class="line" id="L302">};</span>
<span class="line" id="L303"></span>
<span class="line" id="L304"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PAM = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L305"> <span class="tok-comment">//! Portable AnyMap</span></span>
<span class="line" id="L306"> <span class="tok-comment">//! currently, this only supports a subset of PAMs where:</span></span>
<span class="line" id="L307"> <span class="tok-comment">//! - the tuple type is official (see `man 5 pam`) or easily inferred (and</span></span>
<span class="line" id="L308"> <span class="tok-comment">//! by extension, depth is 4 or less)</span></span>
<span class="line" id="L309"> <span class="tok-comment">//! - all images in a sequence have the same dimensions and maxval (it is</span></span>
<span class="line" id="L310"> <span class="tok-comment">//! technically possible to support animations with different maxvals and</span></span>
<span class="line" id="L311"> <span class="tok-comment">//! tuple types as each `AnimationFrame` has its own `PixelStorage`, however,</span></span>
<span class="line" id="L312"> <span class="tok-comment">//! this is likely not expected by users of the library.</span></span>
<span class="line" id="L313"> <span class="tok-comment">//! supported input pixel formats: `grayscale{1, 8, 16}, `grayscale{1, 8, 16}Alpha`, `rgb555`, `{rgb, bgr}{24, 48}`, `{bgr, rgb}a{32, 64}`</span></span>
<span class="line" id="L314"></span>
<span class="line" id="L315"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> EncoderOptions = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L316"> <span class="tok-comment">/// Free-form comments to be added to the header.</span></span>
<span class="line" id="L317"> comments: []<span class="tok-kw">const</span> []<span class="tok-kw">const</span> <span class="tok-type">u8</span> = &amp;.{},</span>
<span class="line" id="L318"> <span class="tok-comment">/// Whether to add the duration of each `Image.AnimationFrame`</span></span>
<span class="line" id="L319"> <span class="tok-comment">/// and the `loop_count` of `Image.Animation` to the written file as a comment.</span></span>
<span class="line" id="L320"> add_duration_as_comment: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L321"> };</span>
<span class="line" id="L322"></span>
<span class="line" id="L323"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatInterface</span>() FormatInterface {</span>
<span class="line" id="L324"> <span class="tok-kw">return</span> FormatInterface{</span>
<span class="line" id="L325"> .format = format,</span>
<span class="line" id="L326"> .formatDetect = formatDetect,</span>
<span class="line" id="L327"> .readImage = readImage,</span>
<span class="line" id="L328"> .writeImage = writeImage,</span>
<span class="line" id="L329"> };</span>
<span class="line" id="L330"> }</span>
<span class="line" id="L331"></span>
<span class="line" id="L332"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">format</span>() Image.Format {</span>
<span class="line" id="L333"> <span class="tok-kw">return</span> Image.Format.pam;</span>
<span class="line" id="L334"> }</span>
<span class="line" id="L335"></span>
<span class="line" id="L336"> <span class="tok-comment">/// Returns `true` if the image will be able to be decoded, or a</span></span>
<span class="line" id="L337"> <span class="tok-comment">/// `stream`-specific error if reading fails.</span></span>
<span class="line" id="L338"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatDetect</span>(stream: *Image.Stream) ImageReadError!<span class="tok-type">bool</span> {</span>
<span class="line" id="L339"> <span class="tok-kw">const</span> magic = <span class="tok-kw">try</span> stream.reader().readBytesNoEof(<span class="tok-number">3</span>);</span>
<span class="line" id="L340"> <span class="tok-kw">return</span> mem.eql(<span class="tok-type">u8</span>, &amp;magic, <span class="tok-str">&quot;P7\n&quot;</span>); <span class="tok-comment">// no possibility of misdetecting xv thumbnails (magic &quot;P7 332&quot;)</span>
</span>
<span class="line" id="L341"> }</span>
<span class="line" id="L342"></span>
<span class="line" id="L343"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readImage</span>(allocator: Allocator, stream: *Image.Stream) ImageReadError!Image {</span>
<span class="line" id="L344"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceReader(stream);</span>
<span class="line" id="L345"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L346"> <span class="tok-kw">var</span> image: Image = <span class="tok-kw">try</span> readFrame(allocator, reader) <span class="tok-kw">orelse</span> <span class="tok-kw">return</span> ImageReadError.InvalidData; <span class="tok-comment">// empty stream</span>
</span>
<span class="line" id="L347"> <span class="tok-kw">errdefer</span> image.deinit();</span>
<span class="line" id="L348"></span>
<span class="line" id="L349"> <span class="tok-kw">while</span> (<span class="tok-kw">try</span> readFrame(allocator, reader)) |frame| {</span>
<span class="line" id="L350"> <span class="tok-kw">if</span> (frame.width != image.width <span class="tok-kw">or</span> frame.height != image.height <span class="tok-kw">or</span> meta.activeTag(frame.pixels) != meta.activeTag(image.pixels)) {</span>
<span class="line" id="L351"> <span class="tok-kw">return</span> ImageReadError.Unsupported; <span class="tok-comment">// no obvious way to have multiple frames with different dimensions</span>
</span>
<span class="line" id="L352"> }</span>
<span class="line" id="L353"> <span class="tok-kw">try</span> image.animation.frames.append(allocator, Image.AnimationFrame{ .pixels = frame.pixels, .duration = <span class="tok-number">0</span> });</span>
<span class="line" id="L354"> }</span>
<span class="line" id="L355"> <span class="tok-kw">return</span> image;</span>
<span class="line" id="L356"> }</span>
<span class="line" id="L357"></span>
<span class="line" id="L358"> <span class="tok-comment">/// Linearly maps `val` from [0..`src_maxval`] to</span></span>
<span class="line" id="L359"> <span class="tok-comment">/// [0..`dst_maxval`]. If `val` is greater than `src_maxval`,</span></span>
<span class="line" id="L360"> <span class="tok-comment">/// `error.OutOfBounds` is returned. If `val == src_maxval`,</span></span>
<span class="line" id="L361"> <span class="tok-comment">/// `dst_maxval` is returned.</span></span>
<span class="line" id="L362"> <span class="tok-kw">fn</span> <span class="tok-fn">mapValue</span>(<span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>, val: T, src_maxval: T, dst_maxval: T) <span class="tok-kw">error</span>{InvalidData}!T {</span>
<span class="line" id="L363"> <span class="tok-kw">if</span> (val &gt; src_maxval) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidData; <span class="tok-comment">// component value exceeded maxval</span>
</span>
<span class="line" id="L364"></span>
<span class="line" id="L365"> <span class="tok-kw">if</span> (src_maxval == dst_maxval) <span class="tok-kw">return</span> val;</span>
<span class="line" id="L366"></span>
<span class="line" id="L367"> <span class="tok-kw">const</span> W = meta.Int(.unsigned, <span class="tok-builtin">@bitSizeOf</span>(T) * <span class="tok-number">2</span>);</span>
<span class="line" id="L368"> <span class="tok-kw">return</span> <span class="tok-builtin">@intCast</span>(<span class="tok-builtin">@min</span>(math.maxInt(T), <span class="tok-builtin">@as</span>(W, dst_maxval) * <span class="tok-builtin">@as</span>(W, val) / <span class="tok-builtin">@as</span>(W, src_maxval)));</span>
<span class="line" id="L369"> }</span>
<span class="line" id="L370"></span>
<span class="line" id="L371"> <span class="tok-kw">fn</span> <span class="tok-fn">readFrame</span>(allocator: Allocator, reader: <span class="tok-kw">anytype</span>) ImageReadError!?Image {</span>
<span class="line" id="L372"> <span class="tok-comment">// we don't use catch switch here because error.EndOfStream</span>
</span>
<span class="line" id="L373"> <span class="tok-comment">// might be the only possible error (and would thus trigger a</span>
</span>
<span class="line" id="L374"> <span class="tok-comment">// compile error because of an unreachable else prong)</span>
</span>
<span class="line" id="L375"> <span class="tok-kw">const</span> magic = reader.readBytesNoEof(<span class="tok-number">3</span>) <span class="tok-kw">catch</span> |e| <span class="tok-kw">return</span> <span class="tok-kw">if</span> (e == <span class="tok-kw">error</span>.EndOfStream) <span class="tok-null">null</span> <span class="tok-kw">else</span> e;</span>
<span class="line" id="L376"> <span class="tok-kw">const</span> is_pam = mem.eql(<span class="tok-type">u8</span>, &amp;magic, <span class="tok-str">&quot;P7\n&quot;</span>);</span>
<span class="line" id="L377"> <span class="tok-kw">if</span> (!is_pam) <span class="tok-kw">return</span> ImageReadError.InvalidData; <span class="tok-comment">// invalid magic number or extraneous data at eof</span>
</span>
<span class="line" id="L378"></span>
<span class="line" id="L379"> <span class="tok-kw">var</span> header = <span class="tok-kw">try</span> Header.read(allocator, reader);</span>
<span class="line" id="L380"> <span class="tok-kw">defer</span> header.deinit(allocator);</span>
<span class="line" id="L381"></span>
<span class="line" id="L382"> <span class="tok-kw">var</span> image: Image = <span class="tok-kw">try</span> header.initImage(allocator);</span>
<span class="line" id="L383"> <span class="tok-kw">errdefer</span> image.deinit();</span>
<span class="line" id="L384"></span>
<span class="line" id="L385"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image.height) |row| {</span>
<span class="line" id="L386"> <span class="tok-kw">const</span> offset = row * image.width;</span>
<span class="line" id="L387"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image.width) |column| {</span>
<span class="line" id="L388"> <span class="tok-kw">switch</span> (image.pixels) {</span>
<span class="line" id="L389"> .grayscale1 =&gt; |g| g[offset + column].value = <span class="tok-builtin">@intCast</span>(<span class="tok-kw">if</span> (header.tuple_type == .mono) <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-number">1</span>, <span class="tok-number">1</span>) <span class="tok-kw">else</span> <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-number">1</span>, <span class="tok-number">1</span>) &amp; <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-number">1</span>, <span class="tok-number">1</span>)),</span>
<span class="line" id="L390"> .grayscale8 =&gt; |g| g[offset + column].value = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L391"> .grayscale8Alpha =&gt; |g| g[offset + column] = .{</span>
<span class="line" id="L392"> .value = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L393"> .alpha = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L394"> },</span>
<span class="line" id="L395"> .grayscale16 =&gt; |g| g[offset + column].value = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L396"> .grayscale16Alpha =&gt; |g| g[offset + column] = .{</span>
<span class="line" id="L397"> .value = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L398"> .alpha = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L399"> },</span>
<span class="line" id="L400"> .rgb24 =&gt; |x| x[offset + column] = .{</span>
<span class="line" id="L401"> .r = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L402"> .g = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L403"> .b = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L404"> },</span>
<span class="line" id="L405"> .rgba32 =&gt; |x| x[offset + column] = .{</span>
<span class="line" id="L406"> .r = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L407"> .g = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L408"> .b = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L409"> .a = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u8</span>, <span class="tok-kw">try</span> reader.readByte(), <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@intCast</span>(header.maxval)), math.maxInt(<span class="tok-type">u8</span>)),</span>
<span class="line" id="L410"> },</span>
<span class="line" id="L411"> .rgb48 =&gt; |x| x[offset + column] = .{</span>
<span class="line" id="L412"> .r = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L413"> .g = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L414"> .b = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L415"> },</span>
<span class="line" id="L416"> .rgba64 =&gt; |x| x[offset + column] = .{</span>
<span class="line" id="L417"> .r = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L418"> .g = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L419"> .b = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L420"> .a = <span class="tok-kw">try</span> mapValue(<span class="tok-type">u16</span>, <span class="tok-kw">try</span> reader.readInt(<span class="tok-type">u16</span>, .little), header.maxval, math.maxInt(<span class="tok-type">u16</span>)),</span>
<span class="line" id="L421"> },</span>
<span class="line" id="L422"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L423"> }</span>
<span class="line" id="L424"> }</span>
<span class="line" id="L425"> }</span>
<span class="line" id="L426"> <span class="tok-kw">return</span> image;</span>
<span class="line" id="L427"> }</span>
<span class="line" id="L428"></span>
<span class="line" id="L429"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(allocator: Allocator, stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L430"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceWriter(stream);</span>
<span class="line" id="L431"> <span class="tok-kw">const</span> writer = buffered_stream.writer();</span>
<span class="line" id="L432"></span>
<span class="line" id="L433"> <span class="tok-kw">var</span> comments = std.ArrayList([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>).init(allocator);</span>
<span class="line" id="L434"> <span class="tok-kw">defer</span> comments.deinit();</span>
<span class="line" id="L435"> <span class="tok-kw">try</span> comments.appendSlice(<span class="tok-kw">switch</span> (encoder_options) {</span>
<span class="line" id="L436"> .pam =&gt; |p| p.comments,</span>
<span class="line" id="L437"> <span class="tok-kw">else</span> =&gt; &amp;.{},</span>
<span class="line" id="L438"> });</span>
<span class="line" id="L439"></span>
<span class="line" id="L440"> <span class="tok-kw">var</span> duration_buffer: [<span class="tok-number">128</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L441"> <span class="tok-kw">const</span> add_duration_as_comment = <span class="tok-kw">switch</span> (encoder_options) {</span>
<span class="line" id="L442"> .pam =&gt; |p| p.add_duration_as_comment,</span>
<span class="line" id="L443"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">false</span>,</span>
<span class="line" id="L444"> };</span>
<span class="line" id="L445"></span>
<span class="line" id="L446"> {</span>
<span class="line" id="L447"> <span class="tok-kw">if</span> (add_duration_as_comment <span class="tok-kw">and</span> image.isAnimation()) {</span>
<span class="line" id="L448"> <span class="tok-kw">try</span> comments.append(<span class="tok-kw">try</span> fmt.bufPrint(&amp;duration_buffer, <span class="tok-str">&quot;loop count: {d}&quot;</span>, .{image.animation.loop_count}));</span>
<span class="line" id="L449"> }</span>
<span class="line" id="L450"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L451"> <span class="tok-kw">if</span> (add_duration_as_comment <span class="tok-kw">and</span> image.isAnimation()) _ = comments.pop();</span>
<span class="line" id="L452"> }</span>
<span class="line" id="L453"></span>
<span class="line" id="L454"> <span class="tok-kw">try</span> writeFrame(writer, image, .{ .pam = .{ .comments = comments.items } });</span>
<span class="line" id="L455"> }</span>
<span class="line" id="L456"></span>
<span class="line" id="L457"> <span class="tok-kw">for</span> (image.animation.frames.items) |frame| {</span>
<span class="line" id="L458"> <span class="tok-kw">if</span> (add_duration_as_comment)</span>
<span class="line" id="L459"> <span class="tok-kw">try</span> comments.append(<span class="tok-kw">try</span> fmt.bufPrint(&amp;duration_buffer, <span class="tok-str">&quot;duration: {d}&quot;</span>, .{frame.duration}));</span>
<span class="line" id="L460"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L461"> <span class="tok-kw">if</span> (add_duration_as_comment) _ = comments.pop();</span>
<span class="line" id="L462"> }</span>
<span class="line" id="L463"></span>
<span class="line" id="L464"> <span class="tok-kw">const</span> frame_img = Image{ .pixels = frame.pixels, .width = image.width, .height = image.height, .allocator = image.allocator };</span>
<span class="line" id="L465"></span>
<span class="line" id="L466"> <span class="tok-kw">try</span> writeFrame(writer, frame_img, .{ .pam = .{ .comments = comments.items } });</span>
<span class="line" id="L467"> }</span>
<span class="line" id="L468"></span>
<span class="line" id="L469"> <span class="tok-kw">try</span> buffered_stream.flush();</span>
<span class="line" id="L470"> }</span>
<span class="line" id="L471"></span>
<span class="line" id="L472"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeFrame</span>(writer: <span class="tok-kw">anytype</span>, frame: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L473"> <span class="tok-kw">var</span> header = <span class="tok-kw">try</span> Header.fromImage(frame);</span>
<span class="line" id="L474"> header.comments = encoder_options.pam.comments;</span>
<span class="line" id="L475"> <span class="tok-kw">try</span> header.write(writer);</span>
<span class="line" id="L476"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..frame.height) |row| {</span>
<span class="line" id="L477"> <span class="tok-kw">const</span> offset = row * frame.width;</span>
<span class="line" id="L478"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..frame.width) |column| {</span>
<span class="line" id="L479"> <span class="tok-kw">switch</span> (frame.pixels) {</span>
<span class="line" id="L480"> .grayscale1 =&gt; |x| <span class="tok-kw">try</span> writer.writeByte(x[offset + column].value),</span>
<span class="line" id="L481"> .grayscale4 =&gt; |x| <span class="tok-kw">try</span> writer.writeByte(x[offset + column].value),</span>
<span class="line" id="L482"> .grayscale8 =&gt; |x| <span class="tok-kw">try</span> writer.writeByte(x[offset + column].value),</span>
<span class="line" id="L483"> .grayscale16 =&gt; |x| <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].value, .little),</span>
<span class="line" id="L484"> .grayscale8Alpha =&gt; |x| {</span>
<span class="line" id="L485"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].value);</span>
<span class="line" id="L486"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].alpha);</span>
<span class="line" id="L487"> },</span>
<span class="line" id="L488"> .grayscale16Alpha =&gt; |x| {</span>
<span class="line" id="L489"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].value, .little);</span>
<span class="line" id="L490"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].alpha, .little);</span>
<span class="line" id="L491"> },</span>
<span class="line" id="L492"> .bgr555 =&gt; |x| {</span>
<span class="line" id="L493"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].r);</span>
<span class="line" id="L494"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].g);</span>
<span class="line" id="L495"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].b);</span>
<span class="line" id="L496"> },</span>
<span class="line" id="L497"> .rgb555 =&gt; |x| {</span>
<span class="line" id="L498"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].r);</span>
<span class="line" id="L499"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].g);</span>
<span class="line" id="L500"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].b);</span>
<span class="line" id="L501"> },</span>
<span class="line" id="L502"> .rgb24 =&gt; |x| {</span>
<span class="line" id="L503"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].r);</span>
<span class="line" id="L504"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].g);</span>
<span class="line" id="L505"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].b);</span>
<span class="line" id="L506"> },</span>
<span class="line" id="L507"> .rgba32 =&gt; |x| {</span>
<span class="line" id="L508"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].r);</span>
<span class="line" id="L509"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].g);</span>
<span class="line" id="L510"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].b);</span>
<span class="line" id="L511"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].a);</span>
<span class="line" id="L512"> },</span>
<span class="line" id="L513"> .bgr24 =&gt; |x| {</span>
<span class="line" id="L514"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].r);</span>
<span class="line" id="L515"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].g);</span>
<span class="line" id="L516"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].b);</span>
<span class="line" id="L517"> },</span>
<span class="line" id="L518"> .bgra32 =&gt; |x| {</span>
<span class="line" id="L519"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].r);</span>
<span class="line" id="L520"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].g);</span>
<span class="line" id="L521"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].b);</span>
<span class="line" id="L522"> <span class="tok-kw">try</span> writer.writeByte(x[offset + column].a);</span>
<span class="line" id="L523"> },</span>
<span class="line" id="L524"> .rgb48 =&gt; |x| {</span>
<span class="line" id="L525"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].r, .little);</span>
<span class="line" id="L526"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].g, .little);</span>
<span class="line" id="L527"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].b, .little);</span>
<span class="line" id="L528"> },</span>
<span class="line" id="L529"> .rgba64 =&gt; |x| {</span>
<span class="line" id="L530"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].r, .little);</span>
<span class="line" id="L531"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].g, .little);</span>
<span class="line" id="L532"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].b, .little);</span>
<span class="line" id="L533"> <span class="tok-kw">try</span> writer.writeInt(<span class="tok-type">u16</span>, x[offset + column].a, .little);</span>
<span class="line" id="L534"> },</span>
<span class="line" id="L535"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>, <span class="tok-comment">// can't happen, already handled in fromImage</span>
</span>
<span class="line" id="L536"> }</span>
<span class="line" id="L537"> }</span>
<span class="line" id="L538"> }</span>
<span class="line" id="L539"> }</span>
<span class="line" id="L540">};</span>
<span class="line" id="L541"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,862 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/pcx.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Adapted from https://github.com/MasterQ32/zig-gamedev-lib/blob/master/src/pcx.zig</span>
</span>
<span class="line" id="L2"><span class="tok-comment">// with permission from Felix Queißner</span>
</span>
<span class="line" id="L3"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../color.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> ImageError = Image.Error;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L10"><span class="tok-kw">const</span> ImageWriteError = Image.WriteError;</span>
<span class="line" id="L11"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L12"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L13"><span class="tok-kw">const</span> utils = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../utils.zig&quot;</span>);</span>
<span class="line" id="L14"><span class="tok-kw">const</span> simd = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../simd.zig&quot;</span>);</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-kw">const</span> MagicHeader: <span class="tok-type">u8</span> = <span class="tok-number">0x0A</span>;</span>
<span class="line" id="L17"><span class="tok-kw">const</span> Version: <span class="tok-type">u8</span> = <span class="tok-number">5</span>;</span>
<span class="line" id="L18"><span class="tok-kw">const</span> VGAPaletteIdentifier: <span class="tok-type">u8</span> = <span class="tok-number">0x0C</span>;</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Compression = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L21"> none,</span>
<span class="line" id="L22"> rle,</span>
<span class="line" id="L23">};</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PaletteInfo = <span class="tok-kw">enum</span>(<span class="tok-type">u16</span>) {</span>
<span class="line" id="L26"> color = <span class="tok-number">1</span>,</span>
<span class="line" id="L27"> grayscale = <span class="tok-number">2</span>,</span>
<span class="line" id="L28"> _,</span>
<span class="line" id="L29">};</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PCXHeader = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L32"> id: <span class="tok-type">u8</span> = MagicHeader,</span>
<span class="line" id="L33"> version: <span class="tok-type">u8</span> = Version,</span>
<span class="line" id="L34"> compression: Compression = .rle,</span>
<span class="line" id="L35"> bpp: <span class="tok-type">u8</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L36"> xmin: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L37"> ymin: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L38"> xmax: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L39"> ymax: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L40"> horizontal_dpi: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">320</span>, <span class="tok-comment">// Default values found in the PCX image in the test suite</span>
</span>
<span class="line" id="L41"> vertical_dpi: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">200</span>, <span class="tok-comment">// Default values found in the PCX image in the test suite</span>
</span>
<span class="line" id="L42"> builtin_palette: [<span class="tok-number">16</span>]color.Rgb24 = [_]color.Rgb24{.{ .r = <span class="tok-number">0</span>, .g = <span class="tok-number">0</span>, .b = <span class="tok-number">0</span> }} ** <span class="tok-number">16</span>,</span>
<span class="line" id="L43"> _reserved0: <span class="tok-type">u8</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L44"> planes: <span class="tok-type">u8</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L45"> stride: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L46"> palette_information: PaletteInfo <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = .color,</span>
<span class="line" id="L47"> screen_width: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L48"> screen_height: <span class="tok-type">u16</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0</span>,</span>
<span class="line" id="L49"> padding: [<span class="tok-number">54</span>]<span class="tok-type">u8</span> = [_]<span class="tok-type">u8</span>{<span class="tok-number">0</span>} ** <span class="tok-number">54</span>,</span>
<span class="line" id="L50"></span>
<span class="line" id="L51"> <span class="tok-kw">comptime</span> {</span>
<span class="line" id="L52"> std.debug.assert(<span class="tok-builtin">@sizeOf</span>(PCXHeader) == <span class="tok-number">128</span>);</span>
<span class="line" id="L53"> }</span>
<span class="line" id="L54">};</span>
<span class="line" id="L55"></span>
<span class="line" id="L56"><span class="tok-kw">const</span> RLEPairMask = <span class="tok-number">0xC0</span>;</span>
<span class="line" id="L57"><span class="tok-kw">const</span> RLELengthMask = <span class="tok-number">0xFF</span> - RLEPairMask;</span>
<span class="line" id="L58"></span>
<span class="line" id="L59"><span class="tok-kw">const</span> RLEDecoder = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L60"> <span class="tok-kw">const</span> Run = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L61"> value: <span class="tok-type">u8</span>,</span>
<span class="line" id="L62"> remaining: <span class="tok-type">usize</span>,</span>
<span class="line" id="L63"> };</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader,</span>
<span class="line" id="L66"> current_run: ?Run,</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(reader: buffered_stream_source.DefaultBufferedStreamSourceReader.Reader) RLEDecoder {</span>
<span class="line" id="L69"> <span class="tok-kw">return</span> RLEDecoder{</span>
<span class="line" id="L70"> .reader = reader,</span>
<span class="line" id="L71"> .current_run = <span class="tok-null">null</span>,</span>
<span class="line" id="L72"> };</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> <span class="tok-kw">fn</span> <span class="tok-fn">readByte</span>(self: *RLEDecoder) ImageReadError!<span class="tok-type">u8</span> {</span>
<span class="line" id="L76"> <span class="tok-kw">if</span> (self.current_run) |*run| {</span>
<span class="line" id="L77"> <span class="tok-kw">const</span> result = run.value;</span>
<span class="line" id="L78"> run.remaining -= <span class="tok-number">1</span>;</span>
<span class="line" id="L79"> <span class="tok-kw">if</span> (run.remaining == <span class="tok-number">0</span>) {</span>
<span class="line" id="L80"> self.current_run = <span class="tok-null">null</span>;</span>
<span class="line" id="L81"> }</span>
<span class="line" id="L82"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L83"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L84"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L85"> <span class="tok-kw">const</span> byte = <span class="tok-kw">try</span> self.reader.readByte();</span>
<span class="line" id="L86"> <span class="tok-kw">if</span> (byte == RLEPairMask) <span class="tok-comment">// skip over &quot;zero length runs&quot;</span>
</span>
<span class="line" id="L87"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L88"> <span class="tok-kw">if</span> ((byte &amp; RLEPairMask) == RLEPairMask) {</span>
<span class="line" id="L89"> <span class="tok-kw">const</span> len = byte &amp; RLELengthMask;</span>
<span class="line" id="L90"> std.debug.assert(len &gt; <span class="tok-number">0</span>);</span>
<span class="line" id="L91"> <span class="tok-kw">const</span> result = <span class="tok-kw">try</span> self.reader.readByte();</span>
<span class="line" id="L92"> <span class="tok-kw">if</span> (len &gt; <span class="tok-number">1</span>) {</span>
<span class="line" id="L93"> <span class="tok-comment">// we only need to store a run in the decoder if it is longer than 1</span>
</span>
<span class="line" id="L94"> self.current_run = .{</span>
<span class="line" id="L95"> .value = result,</span>
<span class="line" id="L96"> .remaining = len - <span class="tok-number">1</span>,</span>
<span class="line" id="L97"> };</span>
<span class="line" id="L98"> }</span>
<span class="line" id="L99"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L100"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L101"> <span class="tok-kw">return</span> byte;</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103"> }</span>
<span class="line" id="L104"> }</span>
<span class="line" id="L105"> }</span>
<span class="line" id="L106"></span>
<span class="line" id="L107"> <span class="tok-kw">fn</span> <span class="tok-fn">finish</span>(decoder: RLEDecoder) ImageReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L108"> <span class="tok-kw">if</span> (decoder.current_run != <span class="tok-null">null</span>) {</span>
<span class="line" id="L109"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L110"> }</span>
<span class="line" id="L111"> }</span>
<span class="line" id="L112">};</span>
<span class="line" id="L113"></span>
<span class="line" id="L114"><span class="tok-kw">const</span> RLEPair = <span class="tok-kw">packed</span> <span class="tok-kw">struct</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L115"> length: <span class="tok-type">u6</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L116"> identifier: <span class="tok-type">u2</span> = (<span class="tok-number">1</span> &lt;&lt; <span class="tok-number">2</span>) - <span class="tok-number">1</span>,</span>
<span class="line" id="L117">};</span>
<span class="line" id="L118"></span>
<span class="line" id="L119"><span class="tok-kw">const</span> RLEMinLength = <span class="tok-number">2</span>;</span>
<span class="line" id="L120"><span class="tok-kw">const</span> RLEMaxLength = (<span class="tok-number">1</span> &lt;&lt; <span class="tok-number">6</span>) - <span class="tok-number">1</span>;</span>
<span class="line" id="L121"></span>
<span class="line" id="L122"><span class="tok-kw">fn</span> <span class="tok-fn">flushRLE</span>(writer: <span class="tok-kw">anytype</span>, value: <span class="tok-type">u8</span>, count: <span class="tok-type">usize</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L123"> <span class="tok-kw">var</span> current_count = count;</span>
<span class="line" id="L124"> <span class="tok-kw">while</span> (current_count &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L125"> <span class="tok-kw">const</span> length_to_write = <span class="tok-builtin">@min</span>(current_count, RLEMaxLength);</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"> <span class="tok-kw">if</span> (length_to_write &gt;= RLEMinLength) {</span>
<span class="line" id="L128"> <span class="tok-kw">try</span> flushRlePair(writer, value, length_to_write);</span>
<span class="line" id="L129"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L130"> <span class="tok-kw">try</span> flushRawBytes(writer, value, length_to_write);</span>
<span class="line" id="L131"> }</span>
<span class="line" id="L132"></span>
<span class="line" id="L133"> current_count -= length_to_write;</span>
<span class="line" id="L134"> }</span>
<span class="line" id="L135">}</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"><span class="tok-kw">inline</span> <span class="tok-kw">fn</span> <span class="tok-fn">flushRlePair</span>(writer: <span class="tok-kw">anytype</span>, value: <span class="tok-type">u8</span>, count: <span class="tok-type">usize</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L138"> <span class="tok-kw">const</span> rle_pair = RLEPair{</span>
<span class="line" id="L139"> .length = <span class="tok-builtin">@truncate</span>(count),</span>
<span class="line" id="L140"> };</span>
<span class="line" id="L141"> <span class="tok-kw">try</span> writer.writeByte(<span class="tok-builtin">@bitCast</span>(rle_pair));</span>
<span class="line" id="L142"> <span class="tok-kw">try</span> writer.writeByte(value);</span>
<span class="line" id="L143">}</span>
<span class="line" id="L144"></span>
<span class="line" id="L145"><span class="tok-kw">inline</span> <span class="tok-kw">fn</span> <span class="tok-fn">flushRawBytes</span>(writer: <span class="tok-kw">anytype</span>, value: <span class="tok-type">u8</span>, count: <span class="tok-type">usize</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L146"> <span class="tok-comment">// Must flush byte greater than 192 (0xC0) as a RLE pair</span>
</span>
<span class="line" id="L147"> <span class="tok-kw">if</span> ((value &amp; RLEPairMask) == RLEPairMask) {</span>
<span class="line" id="L148"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..count) |_| {</span>
<span class="line" id="L149"> <span class="tok-kw">try</span> flushRlePair(writer, value, <span class="tok-number">1</span>);</span>
<span class="line" id="L150"> }</span>
<span class="line" id="L151"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L152"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..count) |_| {</span>
<span class="line" id="L153"> <span class="tok-kw">try</span> writer.writeByte(value);</span>
<span class="line" id="L154"> }</span>
<span class="line" id="L155"> }</span>
<span class="line" id="L156">}</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"><span class="tok-kw">const</span> RLEFastEncoder = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L159"> <span class="tok-kw">const</span> LengthToCheck = <span class="tok-number">16</span>;</span>
<span class="line" id="L160"> <span class="tok-kw">const</span> VectorType = <span class="tok-builtin">@Vector</span>(LengthToCheck, <span class="tok-type">u8</span>);</span>
<span class="line" id="L161"></span>
<span class="line" id="L162"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">encode</span>(source_data: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, writer: <span class="tok-kw">anytype</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L163"> <span class="tok-kw">if</span> (source_data.len == <span class="tok-number">0</span>) {</span>
<span class="line" id="L164"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L165"> }</span>
<span class="line" id="L166"></span>
<span class="line" id="L167"> <span class="tok-kw">var</span> index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L168"></span>
<span class="line" id="L169"> <span class="tok-kw">var</span> total_similar_count: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L170"></span>
<span class="line" id="L171"> <span class="tok-kw">var</span> current_byte: <span class="tok-type">u8</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L172"></span>
<span class="line" id="L173"> <span class="tok-kw">while</span> (index &lt; source_data.len <span class="tok-kw">and</span> (index + LengthToCheck) &lt;= source_data.len) {</span>
<span class="line" id="L174"> <span class="tok-comment">// Read current byte</span>
</span>
<span class="line" id="L175"> current_byte = source_data[index];</span>
<span class="line" id="L176"></span>
<span class="line" id="L177"> <span class="tok-kw">const</span> current_byte_splatted: VectorType = <span class="tok-builtin">@splat</span>(current_byte);</span>
<span class="line" id="L178"> <span class="tok-kw">const</span> compare_chunk = simd.load(source_data[index..], VectorType, <span class="tok-number">0</span>);</span>
<span class="line" id="L179"></span>
<span class="line" id="L180"> <span class="tok-kw">const</span> compare_mask = (current_byte_splatted == compare_chunk);</span>
<span class="line" id="L181"> <span class="tok-kw">const</span> inverted_mask = ~<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@bitCast</span>(compare_mask));</span>
<span class="line" id="L182"> <span class="tok-kw">const</span> current_similar_count = <span class="tok-builtin">@ctz</span>(inverted_mask);</span>
<span class="line" id="L183"></span>
<span class="line" id="L184"> <span class="tok-kw">if</span> (current_similar_count == LengthToCheck) {</span>
<span class="line" id="L185"> total_similar_count += current_similar_count;</span>
<span class="line" id="L186"> index += current_similar_count;</span>
<span class="line" id="L187"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L188"> total_similar_count += current_similar_count;</span>
<span class="line" id="L189"></span>
<span class="line" id="L190"> <span class="tok-kw">try</span> flushRLE(writer, current_byte, total_similar_count);</span>
<span class="line" id="L191"></span>
<span class="line" id="L192"> total_similar_count = <span class="tok-number">0</span>;</span>
<span class="line" id="L193"></span>
<span class="line" id="L194"> index += current_similar_count;</span>
<span class="line" id="L195"> }</span>
<span class="line" id="L196"> }</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-kw">try</span> flushRLE(writer, current_byte, total_similar_count);</span>
<span class="line" id="L199"></span>
<span class="line" id="L200"> <span class="tok-comment">// Process the rest sequentially</span>
</span>
<span class="line" id="L201"> total_similar_count = <span class="tok-number">0</span>;</span>
<span class="line" id="L202"> <span class="tok-kw">if</span> (index &lt; source_data.len) {</span>
<span class="line" id="L203"> current_byte = source_data[index];</span>
<span class="line" id="L204"></span>
<span class="line" id="L205"> <span class="tok-kw">while</span> (index &lt; source_data.len) {</span>
<span class="line" id="L206"> <span class="tok-kw">const</span> read_byte = source_data[index];</span>
<span class="line" id="L207"> <span class="tok-kw">if</span> (read_byte == current_byte) {</span>
<span class="line" id="L208"> total_similar_count += <span class="tok-number">1</span>;</span>
<span class="line" id="L209"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L210"> <span class="tok-kw">try</span> flushRLE(writer, current_byte, total_similar_count);</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> current_byte = read_byte;</span>
<span class="line" id="L213"> total_similar_count = <span class="tok-number">1</span>;</span>
<span class="line" id="L214"> }</span>
<span class="line" id="L215"></span>
<span class="line" id="L216"> index += <span class="tok-number">1</span>;</span>
<span class="line" id="L217"> }</span>
<span class="line" id="L218"></span>
<span class="line" id="L219"> <span class="tok-kw">try</span> flushRLE(writer, current_byte, total_similar_count);</span>
<span class="line" id="L220"> }</span>
<span class="line" id="L221"> }</span>
<span class="line" id="L222">};</span>
<span class="line" id="L223"></span>
<span class="line" id="L224"><span class="tok-kw">test</span> <span class="tok-str">&quot;PCX RLE Fast encoder&quot;</span> {</span>
<span class="line" id="L225"> <span class="tok-kw">const</span> uncompressed_data = [_]<span class="tok-type">u8</span>{ <span class="tok-number">1</span>, <span class="tok-number">1</span>, <span class="tok-number">1</span>, <span class="tok-number">1</span>, <span class="tok-number">1</span>, <span class="tok-number">1</span>, <span class="tok-number">1</span>, <span class="tok-number">1</span>, <span class="tok-number">1</span>, <span class="tok-number">64</span>, <span class="tok-number">64</span>, <span class="tok-number">2</span>, <span class="tok-number">2</span>, <span class="tok-number">2</span>, <span class="tok-number">2</span>, <span class="tok-number">2</span>, <span class="tok-number">215</span>, <span class="tok-number">215</span>, <span class="tok-number">215</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">3</span>, <span class="tok-number">200</span>, <span class="tok-number">200</span>, <span class="tok-number">200</span>, <span class="tok-number">200</span>, <span class="tok-number">210</span>, <span class="tok-number">210</span> };</span>
<span class="line" id="L226"> <span class="tok-kw">const</span> compressed_data = [_]<span class="tok-type">u8</span>{ <span class="tok-number">0xC9</span>, <span class="tok-number">0x01</span>, <span class="tok-number">0xC2</span>, <span class="tok-number">0x40</span>, <span class="tok-number">0xC5</span>, <span class="tok-number">0x02</span>, <span class="tok-number">0xC3</span>, <span class="tok-number">0xD7</span>, <span class="tok-number">0xCA</span>, <span class="tok-number">0x03</span>, <span class="tok-number">0xC4</span>, <span class="tok-number">0xC8</span>, <span class="tok-number">0xC2</span>, <span class="tok-number">0xD2</span> };</span>
<span class="line" id="L227"></span>
<span class="line" id="L228"> <span class="tok-kw">var</span> result_list = std.ArrayList(<span class="tok-type">u8</span>).init(std.testing.allocator);</span>
<span class="line" id="L229"> <span class="tok-kw">defer</span> result_list.deinit();</span>
<span class="line" id="L230"></span>
<span class="line" id="L231"> <span class="tok-kw">const</span> writer = result_list.writer();</span>
<span class="line" id="L232"></span>
<span class="line" id="L233"> <span class="tok-kw">try</span> RLEFastEncoder.encode(uncompressed_data[<span class="tok-number">0</span>..], writer);</span>
<span class="line" id="L234"></span>
<span class="line" id="L235"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, compressed_data[<span class="tok-number">0</span>..], result_list.items);</span>
<span class="line" id="L236">}</span>
<span class="line" id="L237"></span>
<span class="line" id="L238"><span class="tok-kw">test</span> <span class="tok-str">&quot;PCX RLE Fast encoder should encore more than 63 bytes similar&quot;</span> {</span>
<span class="line" id="L239"> <span class="tok-kw">const</span> first_uncompressed_part = [_]<span class="tok-type">u8</span>{<span class="tok-number">0x45</span>} ** <span class="tok-number">65</span>;</span>
<span class="line" id="L240"> <span class="tok-kw">const</span> second_uncompresse_part = [_]<span class="tok-type">u8</span>{ <span class="tok-number">0x1</span>, <span class="tok-number">0x1</span>, <span class="tok-number">0x1</span>, <span class="tok-number">0x1</span> };</span>
<span class="line" id="L241"> <span class="tok-kw">const</span> uncompressed_data = first_uncompressed_part ++ second_uncompresse_part;</span>
<span class="line" id="L242"></span>
<span class="line" id="L243"> <span class="tok-kw">const</span> compressed_data = [_]<span class="tok-type">u8</span>{ <span class="tok-number">0xFF</span>, <span class="tok-number">0x45</span>, <span class="tok-number">0x45</span>, <span class="tok-number">0x45</span>, <span class="tok-number">0xC4</span>, <span class="tok-number">0x1</span> };</span>
<span class="line" id="L244"></span>
<span class="line" id="L245"> <span class="tok-kw">var</span> result_list = std.ArrayList(<span class="tok-type">u8</span>).init(std.testing.allocator);</span>
<span class="line" id="L246"> <span class="tok-kw">defer</span> result_list.deinit();</span>
<span class="line" id="L247"></span>
<span class="line" id="L248"> <span class="tok-kw">const</span> writer = result_list.writer();</span>
<span class="line" id="L249"></span>
<span class="line" id="L250"> <span class="tok-kw">try</span> RLEFastEncoder.encode(uncompressed_data[<span class="tok-number">0</span>..], writer);</span>
<span class="line" id="L251"></span>
<span class="line" id="L252"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, compressed_data[<span class="tok-number">0</span>..], result_list.items);</span>
<span class="line" id="L253">}</span>
<span class="line" id="L254"></span>
<span class="line" id="L255"><span class="tok-kw">const</span> RLEStreamEncoder = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L256"> rle_byte: ?<span class="tok-type">u8</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L257"> length: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L258"></span>
<span class="line" id="L259"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">encode</span>(self: *RLEStreamEncoder, writer: <span class="tok-kw">anytype</span>, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L260"> <span class="tok-kw">for</span> (bytes) |byte| {</span>
<span class="line" id="L261"> <span class="tok-kw">try</span> self.encodeByte(writer, byte);</span>
<span class="line" id="L262"> }</span>
<span class="line" id="L263"> }</span>
<span class="line" id="L264"></span>
<span class="line" id="L265"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">encodeByte</span>(self: *RLEStreamEncoder, writer: <span class="tok-kw">anytype</span>, byte: <span class="tok-type">u8</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L266"> <span class="tok-kw">if</span> (self.rle_byte == <span class="tok-null">null</span>) {</span>
<span class="line" id="L267"> self.rle_byte = byte;</span>
<span class="line" id="L268"> self.length = <span class="tok-number">1</span>;</span>
<span class="line" id="L269"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L270"> }</span>
<span class="line" id="L271"></span>
<span class="line" id="L272"> <span class="tok-kw">if</span> (self.rle_byte) |rle_byte| {</span>
<span class="line" id="L273"> <span class="tok-kw">if</span> (rle_byte == byte) {</span>
<span class="line" id="L274"> self.length += <span class="tok-number">1</span>;</span>
<span class="line" id="L275"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L276"> <span class="tok-kw">try</span> flushRLE(writer, rle_byte, self.length);</span>
<span class="line" id="L277"></span>
<span class="line" id="L278"> self.length = <span class="tok-number">1</span>;</span>
<span class="line" id="L279"> self.rle_byte = byte;</span>
<span class="line" id="L280"> }</span>
<span class="line" id="L281"> }</span>
<span class="line" id="L282"> }</span>
<span class="line" id="L283"></span>
<span class="line" id="L284"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">flush</span>(self: *RLEStreamEncoder, writer: <span class="tok-kw">anytype</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L285"> <span class="tok-kw">if</span> (self.length == <span class="tok-number">0</span>) {</span>
<span class="line" id="L286"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L287"> }</span>
<span class="line" id="L288"></span>
<span class="line" id="L289"> <span class="tok-kw">if</span> (self.rle_byte) |check_byte| {</span>
<span class="line" id="L290"> <span class="tok-kw">try</span> flushRLE(writer, check_byte, self.length);</span>
<span class="line" id="L291"> }</span>
<span class="line" id="L292"> }</span>
<span class="line" id="L293">};</span>
<span class="line" id="L294"></span>
<span class="line" id="L295"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PCX = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L296"> header: PCXHeader = .{},</span>
<span class="line" id="L297"></span>
<span class="line" id="L298"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> EncoderOptions = <span class="tok-kw">struct</span> {};</span>
<span class="line" id="L299"></span>
<span class="line" id="L300"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatInterface</span>() FormatInterface {</span>
<span class="line" id="L301"> <span class="tok-kw">return</span> FormatInterface{</span>
<span class="line" id="L302"> .format = format,</span>
<span class="line" id="L303"> .formatDetect = formatDetect,</span>
<span class="line" id="L304"> .readImage = readImage,</span>
<span class="line" id="L305"> .writeImage = writeImage,</span>
<span class="line" id="L306"> };</span>
<span class="line" id="L307"> }</span>
<span class="line" id="L308"></span>
<span class="line" id="L309"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">format</span>() Image.Format {</span>
<span class="line" id="L310"> <span class="tok-kw">return</span> Image.Format.pcx;</span>
<span class="line" id="L311"> }</span>
<span class="line" id="L312"></span>
<span class="line" id="L313"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatDetect</span>(stream: *Image.Stream) ImageReadError!<span class="tok-type">bool</span> {</span>
<span class="line" id="L314"> <span class="tok-kw">var</span> magic_number_bufffer: [<span class="tok-number">2</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L315"> _ = <span class="tok-kw">try</span> stream.read(magic_number_bufffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L316"></span>
<span class="line" id="L317"> <span class="tok-kw">if</span> (magic_number_bufffer[<span class="tok-number">0</span>] != MagicHeader) {</span>
<span class="line" id="L318"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L319"> }</span>
<span class="line" id="L320"></span>
<span class="line" id="L321"> <span class="tok-kw">if</span> (magic_number_bufffer[<span class="tok-number">1</span>] &gt; Version) {</span>
<span class="line" id="L322"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L323"> }</span>
<span class="line" id="L324"></span>
<span class="line" id="L325"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L326"> }</span>
<span class="line" id="L327"></span>
<span class="line" id="L328"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readImage</span>(allocator: Allocator, stream: *Image.Stream) ImageReadError!Image {</span>
<span class="line" id="L329"> <span class="tok-kw">var</span> result = Image.init(allocator);</span>
<span class="line" id="L330"> <span class="tok-kw">errdefer</span> result.deinit();</span>
<span class="line" id="L331"> <span class="tok-kw">var</span> pcx = PCX{};</span>
<span class="line" id="L332"></span>
<span class="line" id="L333"> <span class="tok-kw">const</span> pixels = <span class="tok-kw">try</span> pcx.read(allocator, stream);</span>
<span class="line" id="L334"></span>
<span class="line" id="L335"> result.width = pcx.width();</span>
<span class="line" id="L336"> result.height = pcx.height();</span>
<span class="line" id="L337"> result.pixels = pixels;</span>
<span class="line" id="L338"></span>
<span class="line" id="L339"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L340"> }</span>
<span class="line" id="L341"></span>
<span class="line" id="L342"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(allocator: Allocator, stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L343"> _ = allocator;</span>
<span class="line" id="L344"> _ = encoder_options;</span>
<span class="line" id="L345"></span>
<span class="line" id="L346"> <span class="tok-kw">var</span> pcx = PCX{};</span>
<span class="line" id="L347"></span>
<span class="line" id="L348"> <span class="tok-kw">if</span> (image.width &gt; std.math.maxInt(<span class="tok-type">u16</span>) <span class="tok-kw">or</span> image.height &gt; std.math.maxInt(<span class="tok-type">u16</span>)) {</span>
<span class="line" id="L349"> <span class="tok-kw">return</span> ImageWriteError.Unsupported;</span>
<span class="line" id="L350"> }</span>
<span class="line" id="L351"></span>
<span class="line" id="L352"> pcx.header.xmax = <span class="tok-builtin">@truncate</span>(image.width - <span class="tok-number">1</span>);</span>
<span class="line" id="L353"> pcx.header.ymax = <span class="tok-builtin">@truncate</span>(image.height - <span class="tok-number">1</span>);</span>
<span class="line" id="L354"></span>
<span class="line" id="L355"> <span class="tok-comment">// Fill header info based on image</span>
</span>
<span class="line" id="L356"> <span class="tok-kw">switch</span> (image.pixels) {</span>
<span class="line" id="L357"> .indexed1 =&gt; |pixels| {</span>
<span class="line" id="L358"> pcx.header.bpp = <span class="tok-number">1</span>;</span>
<span class="line" id="L359"> pcx.header.planes = <span class="tok-number">1</span>;</span>
<span class="line" id="L360"></span>
<span class="line" id="L361"> pcx.fillPalette(pixels.palette);</span>
<span class="line" id="L362"> },</span>
<span class="line" id="L363"> .indexed4 =&gt; |pixels| {</span>
<span class="line" id="L364"> pcx.header.bpp = <span class="tok-number">4</span>;</span>
<span class="line" id="L365"> pcx.header.planes = <span class="tok-number">1</span>;</span>
<span class="line" id="L366"></span>
<span class="line" id="L367"> pcx.fillPalette(pixels.palette);</span>
<span class="line" id="L368"> },</span>
<span class="line" id="L369"> .indexed8 =&gt; {</span>
<span class="line" id="L370"> pcx.header.bpp = <span class="tok-number">8</span>;</span>
<span class="line" id="L371"> pcx.header.planes = <span class="tok-number">1</span>;</span>
<span class="line" id="L372"> },</span>
<span class="line" id="L373"> .rgb24 =&gt; {</span>
<span class="line" id="L374"> pcx.header.bpp = <span class="tok-number">8</span>;</span>
<span class="line" id="L375"> pcx.header.planes = <span class="tok-number">3</span>;</span>
<span class="line" id="L376"> },</span>
<span class="line" id="L377"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L378"> <span class="tok-kw">return</span> ImageWriteError.Unsupported;</span>
<span class="line" id="L379"> },</span>
<span class="line" id="L380"> }</span>
<span class="line" id="L381"></span>
<span class="line" id="L382"> pcx.header.stride = <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intFromFloat</span>((<span class="tok-builtin">@as</span>(<span class="tok-type">f32</span>, <span class="tok-builtin">@floatFromInt</span>(image.width)) / <span class="tok-number">8.0</span>) * <span class="tok-builtin">@as</span>(<span class="tok-type">f32</span>, <span class="tok-builtin">@floatFromInt</span>(pcx.header.bpp))));</span>
<span class="line" id="L383"> <span class="tok-comment">// Add one if the result is a odd number</span>
</span>
<span class="line" id="L384"> pcx.header.stride += (pcx.header.stride &amp; <span class="tok-number">0x1</span>);</span>
<span class="line" id="L385"></span>
<span class="line" id="L386"> <span class="tok-kw">try</span> pcx.write(stream, image.pixels);</span>
<span class="line" id="L387"> }</span>
<span class="line" id="L388"></span>
<span class="line" id="L389"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pixelFormat</span>(self: PCX) ImageReadError!PixelFormat {</span>
<span class="line" id="L390"> <span class="tok-kw">if</span> (self.header.planes == <span class="tok-number">1</span>) {</span>
<span class="line" id="L391"> <span class="tok-kw">switch</span> (self.header.bpp) {</span>
<span class="line" id="L392"> <span class="tok-number">1</span> =&gt; <span class="tok-kw">return</span> PixelFormat.indexed1,</span>
<span class="line" id="L393"> <span class="tok-number">4</span> =&gt; <span class="tok-kw">return</span> PixelFormat.indexed4,</span>
<span class="line" id="L394"> <span class="tok-number">8</span> =&gt; <span class="tok-kw">return</span> PixelFormat.indexed8,</span>
<span class="line" id="L395"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L396"> }</span>
<span class="line" id="L397"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (self.header.planes == <span class="tok-number">3</span>) {</span>
<span class="line" id="L398"> <span class="tok-kw">switch</span> (self.header.bpp) {</span>
<span class="line" id="L399"> <span class="tok-number">8</span> =&gt; <span class="tok-kw">return</span> PixelFormat.rgb24,</span>
<span class="line" id="L400"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L401"> }</span>
<span class="line" id="L402"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L403"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L404"> }</span>
<span class="line" id="L405"> }</span>
<span class="line" id="L406"></span>
<span class="line" id="L407"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">width</span>(self: PCX) <span class="tok-type">usize</span> {</span>
<span class="line" id="L408"> <span class="tok-kw">return</span> self.header.xmax - self.header.xmin + <span class="tok-number">1</span>;</span>
<span class="line" id="L409"> }</span>
<span class="line" id="L410"></span>
<span class="line" id="L411"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">height</span>(self: PCX) <span class="tok-type">usize</span> {</span>
<span class="line" id="L412"> <span class="tok-kw">return</span> self.header.ymax - self.header.ymin + <span class="tok-number">1</span>;</span>
<span class="line" id="L413"> }</span>
<span class="line" id="L414"></span>
<span class="line" id="L415"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(self: *PCX, allocator: Allocator, stream: *Image.Stream) ImageReadError!color.PixelStorage {</span>
<span class="line" id="L416"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceReader(stream);</span>
<span class="line" id="L417"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L418"> self.header = <span class="tok-kw">try</span> utils.readStruct(reader, PCXHeader, .little);</span>
<span class="line" id="L419"></span>
<span class="line" id="L420"> <span class="tok-kw">if</span> (self.header.id != <span class="tok-number">0x0A</span>) {</span>
<span class="line" id="L421"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L422"> }</span>
<span class="line" id="L423"></span>
<span class="line" id="L424"> <span class="tok-kw">if</span> (self.header.version &gt; <span class="tok-number">0x05</span>) {</span>
<span class="line" id="L425"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L426"> }</span>
<span class="line" id="L427"></span>
<span class="line" id="L428"> <span class="tok-kw">if</span> (self.header.planes &gt; <span class="tok-number">3</span>) {</span>
<span class="line" id="L429"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L430"> }</span>
<span class="line" id="L431"></span>
<span class="line" id="L432"> <span class="tok-kw">const</span> pixel_format = <span class="tok-kw">try</span> self.pixelFormat();</span>
<span class="line" id="L433"></span>
<span class="line" id="L434"> <span class="tok-kw">const</span> image_width = self.width();</span>
<span class="line" id="L435"> <span class="tok-kw">const</span> image_height = self.height();</span>
<span class="line" id="L436"></span>
<span class="line" id="L437"> <span class="tok-kw">const</span> has_dummy_byte = (<span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, <span class="tok-builtin">@bitCast</span>(self.header.stride)) - <span class="tok-builtin">@as</span>(<span class="tok-type">isize</span>, <span class="tok-builtin">@bitCast</span>(image_width))) == <span class="tok-number">1</span>;</span>
<span class="line" id="L438"> <span class="tok-kw">const</span> actual_width = <span class="tok-kw">if</span> (has_dummy_byte) image_width + <span class="tok-number">1</span> <span class="tok-kw">else</span> image_width;</span>
<span class="line" id="L439"></span>
<span class="line" id="L440"> <span class="tok-kw">var</span> pixels = <span class="tok-kw">try</span> color.PixelStorage.init(allocator, pixel_format, image_width * image_height);</span>
<span class="line" id="L441"> <span class="tok-kw">errdefer</span> pixels.deinit(allocator);</span>
<span class="line" id="L442"></span>
<span class="line" id="L443"> <span class="tok-kw">var</span> decoder = RLEDecoder.init(reader);</span>
<span class="line" id="L444"></span>
<span class="line" id="L445"> <span class="tok-kw">const</span> scanline_length = (self.header.stride * self.header.planes);</span>
<span class="line" id="L446"></span>
<span class="line" id="L447"> <span class="tok-kw">var</span> y: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L448"> <span class="tok-kw">while</span> (y &lt; image_height) : (y += <span class="tok-number">1</span>) {</span>
<span class="line" id="L449"> <span class="tok-kw">var</span> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L450"> <span class="tok-kw">var</span> x: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L451"></span>
<span class="line" id="L452"> <span class="tok-kw">const</span> y_stride = y * image_width;</span>
<span class="line" id="L453"></span>
<span class="line" id="L454"> <span class="tok-comment">// read all pixels from the current row</span>
</span>
<span class="line" id="L455"> <span class="tok-kw">while</span> (offset &lt; scanline_length <span class="tok-kw">and</span> x &lt; image_width) : (offset += <span class="tok-number">1</span>) {</span>
<span class="line" id="L456"> <span class="tok-kw">const</span> byte = <span class="tok-kw">try</span> decoder.readByte();</span>
<span class="line" id="L457"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L458"> .indexed1 =&gt; |storage| {</span>
<span class="line" id="L459"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L460"> <span class="tok-kw">while</span> (i &lt; <span class="tok-number">8</span>) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L461"> <span class="tok-kw">if</span> (x &lt; image_width) {</span>
<span class="line" id="L462"> storage.indices[y_stride + x] = <span class="tok-builtin">@intCast</span>((byte &gt;&gt; (<span class="tok-number">7</span> - <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(i)))) &amp; <span class="tok-number">0x01</span>);</span>
<span class="line" id="L463"> x += <span class="tok-number">1</span>;</span>
<span class="line" id="L464"> }</span>
<span class="line" id="L465"> }</span>
<span class="line" id="L466"> },</span>
<span class="line" id="L467"> .indexed4 =&gt; |storage| {</span>
<span class="line" id="L468"> storage.indices[y_stride + x] = <span class="tok-builtin">@truncate</span>(byte &gt;&gt; <span class="tok-number">4</span>);</span>
<span class="line" id="L469"> x += <span class="tok-number">1</span>;</span>
<span class="line" id="L470"> <span class="tok-kw">if</span> (x &lt; image_width) {</span>
<span class="line" id="L471"> storage.indices[y_stride + x] = <span class="tok-builtin">@truncate</span>(byte);</span>
<span class="line" id="L472"> x += <span class="tok-number">1</span>;</span>
<span class="line" id="L473"> }</span>
<span class="line" id="L474"> },</span>
<span class="line" id="L475"> .indexed8 =&gt; |storage| {</span>
<span class="line" id="L476"> storage.indices[y_stride + x] = byte;</span>
<span class="line" id="L477"> x += <span class="tok-number">1</span>;</span>
<span class="line" id="L478"> },</span>
<span class="line" id="L479"> .rgb24 =&gt; |storage| {</span>
<span class="line" id="L480"> <span class="tok-kw">if</span> (has_dummy_byte <span class="tok-kw">and</span> byte == <span class="tok-number">0x00</span>) {</span>
<span class="line" id="L481"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L482"> }</span>
<span class="line" id="L483"> <span class="tok-kw">const</span> pixel_x = offset % (actual_width);</span>
<span class="line" id="L484"> <span class="tok-kw">const</span> current_color = offset / (actual_width);</span>
<span class="line" id="L485"> <span class="tok-kw">switch</span> (current_color) {</span>
<span class="line" id="L486"> <span class="tok-number">0</span> =&gt; {</span>
<span class="line" id="L487"> storage[y_stride + pixel_x].r = byte;</span>
<span class="line" id="L488"> },</span>
<span class="line" id="L489"> <span class="tok-number">1</span> =&gt; {</span>
<span class="line" id="L490"> storage[y_stride + pixel_x].g = byte;</span>
<span class="line" id="L491"> },</span>
<span class="line" id="L492"> <span class="tok-number">2</span> =&gt; {</span>
<span class="line" id="L493"> storage[y_stride + pixel_x].b = byte;</span>
<span class="line" id="L494"> },</span>
<span class="line" id="L495"> <span class="tok-kw">else</span> =&gt; {},</span>
<span class="line" id="L496"> }</span>
<span class="line" id="L497"></span>
<span class="line" id="L498"> <span class="tok-kw">if</span> (pixel_x &gt; <span class="tok-number">0</span> <span class="tok-kw">and</span> (pixel_x % self.header.planes) == <span class="tok-number">0</span>) {</span>
<span class="line" id="L499"> x += <span class="tok-number">1</span>;</span>
<span class="line" id="L500"> }</span>
<span class="line" id="L501"> },</span>
<span class="line" id="L502"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L503"> }</span>
<span class="line" id="L504"> }</span>
<span class="line" id="L505"></span>
<span class="line" id="L506"> <span class="tok-comment">// discard the rest of the bytes in the current row</span>
</span>
<span class="line" id="L507"> <span class="tok-kw">while</span> (offset &lt; self.header.stride) : (offset += <span class="tok-number">1</span>) {</span>
<span class="line" id="L508"> _ = <span class="tok-kw">try</span> decoder.readByte();</span>
<span class="line" id="L509"> }</span>
<span class="line" id="L510"> }</span>
<span class="line" id="L511"></span>
<span class="line" id="L512"> <span class="tok-kw">try</span> decoder.finish();</span>
<span class="line" id="L513"></span>
<span class="line" id="L514"> <span class="tok-kw">if</span> (pixel_format == .indexed1 <span class="tok-kw">or</span> pixel_format == .indexed4 <span class="tok-kw">or</span> pixel_format == .indexed8) {</span>
<span class="line" id="L515"> <span class="tok-kw">var</span> palette = <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L516"> .indexed1 =&gt; |*storage| storage.palette[<span class="tok-number">0</span>..],</span>
<span class="line" id="L517"> .indexed4 =&gt; |*storage| storage.palette[<span class="tok-number">0</span>..],</span>
<span class="line" id="L518"> .indexed8 =&gt; |*storage| storage.palette[<span class="tok-number">0</span>..],</span>
<span class="line" id="L519"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">undefined</span>,</span>
<span class="line" id="L520"> };</span>
<span class="line" id="L521"></span>
<span class="line" id="L522"> <span class="tok-kw">const</span> effective_len = <span class="tok-builtin">@min</span>(palette.len, self.header.builtin_palette.len);</span>
<span class="line" id="L523"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..effective_len) |index| {</span>
<span class="line" id="L524"> palette[index].r = self.header.builtin_palette[index].r;</span>
<span class="line" id="L525"> palette[index].g = self.header.builtin_palette[index].g;</span>
<span class="line" id="L526"> palette[index].b = self.header.builtin_palette[index].b;</span>
<span class="line" id="L527"> palette[index].a = <span class="tok-number">255</span>;</span>
<span class="line" id="L528"> }</span>
<span class="line" id="L529"></span>
<span class="line" id="L530"> <span class="tok-kw">if</span> (pixels == .indexed8) {</span>
<span class="line" id="L531"> <span class="tok-kw">const</span> end_pos = <span class="tok-kw">try</span> buffered_stream.getEndPos();</span>
<span class="line" id="L532"> <span class="tok-kw">try</span> buffered_stream.seekTo(end_pos - <span class="tok-number">769</span>);</span>
<span class="line" id="L533"></span>
<span class="line" id="L534"> <span class="tok-kw">if</span> ((<span class="tok-kw">try</span> reader.readByte()) != VGAPaletteIdentifier) {</span>
<span class="line" id="L535"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L536"> }</span>
<span class="line" id="L537"></span>
<span class="line" id="L538"> <span class="tok-kw">for</span> (palette) |*current_entry| {</span>
<span class="line" id="L539"> current_entry.r = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L540"> current_entry.g = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L541"> current_entry.b = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L542"> current_entry.a = <span class="tok-number">255</span>;</span>
<span class="line" id="L543"> }</span>
<span class="line" id="L544"> }</span>
<span class="line" id="L545"> }</span>
<span class="line" id="L546"></span>
<span class="line" id="L547"> <span class="tok-kw">return</span> pixels;</span>
<span class="line" id="L548"> }</span>
<span class="line" id="L549"></span>
<span class="line" id="L550"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: PCX, stream: *Image.Stream, pixels: color.PixelStorage) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L551"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L552"> .indexed1,</span>
<span class="line" id="L553"> .indexed4,</span>
<span class="line" id="L554"> .indexed8,</span>
<span class="line" id="L555"> .rgb24,</span>
<span class="line" id="L556"> =&gt; {</span>
<span class="line" id="L557"> <span class="tok-comment">// Do nothing</span>
</span>
<span class="line" id="L558"> },</span>
<span class="line" id="L559"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L560"> <span class="tok-kw">return</span> ImageWriteError.Unsupported;</span>
<span class="line" id="L561"> },</span>
<span class="line" id="L562"> }</span>
<span class="line" id="L563"></span>
<span class="line" id="L564"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceWriter(stream);</span>
<span class="line" id="L565"></span>
<span class="line" id="L566"> <span class="tok-kw">const</span> writer = buffered_stream.writer();</span>
<span class="line" id="L567"></span>
<span class="line" id="L568"> <span class="tok-kw">try</span> utils.writeStruct(writer, self.header, .little);</span>
<span class="line" id="L569"></span>
<span class="line" id="L570"> <span class="tok-kw">const</span> actual_width = self.width();</span>
<span class="line" id="L571"> <span class="tok-kw">const</span> is_even = ((actual_width &amp; <span class="tok-number">0x1</span>) == <span class="tok-number">0</span>);</span>
<span class="line" id="L572"></span>
<span class="line" id="L573"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L574"> .indexed1 =&gt; |indexed| {</span>
<span class="line" id="L575"> <span class="tok-kw">try</span> self.writeIndexed1(writer, indexed);</span>
<span class="line" id="L576"> },</span>
<span class="line" id="L577"> .indexed4 =&gt; |indexed| {</span>
<span class="line" id="L578"> <span class="tok-kw">try</span> self.writeIndexed4(writer, indexed);</span>
<span class="line" id="L579"> },</span>
<span class="line" id="L580"> .indexed8 =&gt; |indexed| {</span>
<span class="line" id="L581"> <span class="tok-kw">if</span> (is_even) {</span>
<span class="line" id="L582"> <span class="tok-kw">try</span> writeIndexed8Even(writer, indexed);</span>
<span class="line" id="L583"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L584"> <span class="tok-kw">try</span> self.writeIndexed8Odd(writer, indexed);</span>
<span class="line" id="L585"> }</span>
<span class="line" id="L586"></span>
<span class="line" id="L587"> <span class="tok-comment">// Write VGA palette</span>
</span>
<span class="line" id="L588"> <span class="tok-kw">try</span> writer.writeByte(VGAPaletteIdentifier);</span>
<span class="line" id="L589"> <span class="tok-kw">for</span> (pixels.indexed8.palette) |current_entry| {</span>
<span class="line" id="L590"> <span class="tok-kw">const</span> rgb24_color = color.Rgb24.fromU32Rgba(current_entry.toU32Rgba());</span>
<span class="line" id="L591"> <span class="tok-kw">try</span> utils.writeStruct(writer, rgb24_color, .little);</span>
<span class="line" id="L592"> }</span>
<span class="line" id="L593"> },</span>
<span class="line" id="L594"> .rgb24 =&gt; |data| {</span>
<span class="line" id="L595"> <span class="tok-kw">try</span> self.writeRgb24(writer, data);</span>
<span class="line" id="L596"> },</span>
<span class="line" id="L597"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L598"> <span class="tok-kw">return</span> ImageWriteError.Unsupported;</span>
<span class="line" id="L599"> },</span>
<span class="line" id="L600"> }</span>
<span class="line" id="L601"></span>
<span class="line" id="L602"> <span class="tok-kw">try</span> buffered_stream.flush();</span>
<span class="line" id="L603"> }</span>
<span class="line" id="L604"></span>
<span class="line" id="L605"> <span class="tok-kw">fn</span> <span class="tok-fn">fillPalette</span>(self: *PCX, palette: []<span class="tok-kw">const</span> color.Rgba32) <span class="tok-type">void</span> {</span>
<span class="line" id="L606"> <span class="tok-kw">const</span> effective_len = <span class="tok-builtin">@min</span>(palette.len, self.header.builtin_palette.len);</span>
<span class="line" id="L607"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..effective_len) |index| {</span>
<span class="line" id="L608"> self.header.builtin_palette[index].r = palette[index].r;</span>
<span class="line" id="L609"> self.header.builtin_palette[index].g = palette[index].g;</span>
<span class="line" id="L610"> self.header.builtin_palette[index].b = palette[index].b;</span>
<span class="line" id="L611"> }</span>
<span class="line" id="L612"> }</span>
<span class="line" id="L613"></span>
<span class="line" id="L614"> <span class="tok-kw">fn</span> <span class="tok-fn">writeIndexed1</span>(self: *<span class="tok-kw">const</span> PCX, writer: buffered_stream_source.DefaultBufferedStreamSourceWriter.Writer, indexed: color.IndexedStorage1) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L615"> <span class="tok-kw">var</span> rle_encoder = RLEStreamEncoder{};</span>
<span class="line" id="L616"></span>
<span class="line" id="L617"> <span class="tok-kw">const</span> image_width = self.width();</span>
<span class="line" id="L618"> <span class="tok-kw">const</span> image_height = self.height();</span>
<span class="line" id="L619"></span>
<span class="line" id="L620"> <span class="tok-kw">const</span> is_even = ((image_width &amp; <span class="tok-number">0x1</span>) == <span class="tok-number">0</span>);</span>
<span class="line" id="L621"></span>
<span class="line" id="L622"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image_height) |y| {</span>
<span class="line" id="L623"> <span class="tok-kw">const</span> stride = y * image_width;</span>
<span class="line" id="L624"></span>
<span class="line" id="L625"> <span class="tok-kw">var</span> current_byte: <span class="tok-type">u8</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L626"></span>
<span class="line" id="L627"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image_width) |x| {</span>
<span class="line" id="L628"> <span class="tok-kw">const</span> pixel = indexed.indices[stride + x];</span>
<span class="line" id="L629"></span>
<span class="line" id="L630"> <span class="tok-kw">const</span> bit = <span class="tok-builtin">@as</span>(<span class="tok-type">u3</span>, <span class="tok-builtin">@intCast</span>(<span class="tok-number">7</span> - (x % <span class="tok-number">8</span>)));</span>
<span class="line" id="L631"></span>
<span class="line" id="L632"> current_byte |= <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, pixel) &lt;&lt; bit;</span>
<span class="line" id="L633"> <span class="tok-kw">if</span> (bit == <span class="tok-number">0</span>) {</span>
<span class="line" id="L634"> <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, current_byte);</span>
<span class="line" id="L635"> current_byte = <span class="tok-number">0</span>;</span>
<span class="line" id="L636"> }</span>
<span class="line" id="L637"> }</span>
<span class="line" id="L638"></span>
<span class="line" id="L639"> <span class="tok-kw">if</span> (!is_even) {</span>
<span class="line" id="L640"> <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, current_byte);</span>
<span class="line" id="L641"> }</span>
<span class="line" id="L642"> }</span>
<span class="line" id="L643"></span>
<span class="line" id="L644"> <span class="tok-kw">try</span> rle_encoder.flush(writer);</span>
<span class="line" id="L645"> }</span>
<span class="line" id="L646"></span>
<span class="line" id="L647"> <span class="tok-kw">fn</span> <span class="tok-fn">writeIndexed4</span>(self: *<span class="tok-kw">const</span> PCX, writer: buffered_stream_source.DefaultBufferedStreamSourceWriter.Writer, indexed: color.IndexedStorage4) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L648"> <span class="tok-kw">var</span> rle_encoder = RLEStreamEncoder{};</span>
<span class="line" id="L649"></span>
<span class="line" id="L650"> <span class="tok-kw">const</span> image_width = self.width();</span>
<span class="line" id="L651"> <span class="tok-kw">const</span> image_height = self.height();</span>
<span class="line" id="L652"></span>
<span class="line" id="L653"> <span class="tok-kw">const</span> is_even = ((image_width &amp; <span class="tok-number">0x1</span>) == <span class="tok-number">0</span>);</span>
<span class="line" id="L654"></span>
<span class="line" id="L655"> <span class="tok-kw">var</span> current_byte: <span class="tok-type">u8</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L656"></span>
<span class="line" id="L657"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image_height) |y| {</span>
<span class="line" id="L658"> <span class="tok-kw">const</span> stride = y * image_width;</span>
<span class="line" id="L659"></span>
<span class="line" id="L660"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image_width) |x| {</span>
<span class="line" id="L661"> <span class="tok-kw">const</span> pixel = indexed.indices[stride + x];</span>
<span class="line" id="L662"></span>
<span class="line" id="L663"> <span class="tok-kw">if</span> ((x &amp; <span class="tok-number">0x1</span>) == <span class="tok-number">0x1</span>) {</span>
<span class="line" id="L664"> current_byte |= pixel;</span>
<span class="line" id="L665"> <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, current_byte);</span>
<span class="line" id="L666"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L667"> current_byte = <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, pixel) &lt;&lt; <span class="tok-number">4</span>;</span>
<span class="line" id="L668"> }</span>
<span class="line" id="L669"> }</span>
<span class="line" id="L670"></span>
<span class="line" id="L671"> <span class="tok-kw">if</span> (!is_even) {</span>
<span class="line" id="L672"> <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, current_byte);</span>
<span class="line" id="L673"> }</span>
<span class="line" id="L674"> }</span>
<span class="line" id="L675"></span>
<span class="line" id="L676"> <span class="tok-kw">try</span> rle_encoder.flush(writer);</span>
<span class="line" id="L677"> }</span>
<span class="line" id="L678"></span>
<span class="line" id="L679"> <span class="tok-kw">fn</span> <span class="tok-fn">writeIndexed8Even</span>(writer: buffered_stream_source.DefaultBufferedStreamSourceWriter.Writer, indexed: color.IndexedStorage8) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L680"> <span class="tok-kw">try</span> RLEFastEncoder.encode(indexed.indices, writer);</span>
<span class="line" id="L681"> }</span>
<span class="line" id="L682"></span>
<span class="line" id="L683"> <span class="tok-kw">fn</span> <span class="tok-fn">writeIndexed8Odd</span>(self: *<span class="tok-kw">const</span> PCX, writer: buffered_stream_source.DefaultBufferedStreamSourceWriter.Writer, indexed: color.IndexedStorage8) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L684"> <span class="tok-kw">var</span> rle_encoder = RLEStreamEncoder{};</span>
<span class="line" id="L685"></span>
<span class="line" id="L686"> <span class="tok-kw">const</span> image_width = self.width();</span>
<span class="line" id="L687"> <span class="tok-kw">const</span> image_height = self.height();</span>
<span class="line" id="L688"></span>
<span class="line" id="L689"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image_height) |y| {</span>
<span class="line" id="L690"> <span class="tok-kw">const</span> y_stride = y * image_width;</span>
<span class="line" id="L691"></span>
<span class="line" id="L692"> <span class="tok-kw">const</span> pixel_stride = indexed.indices[y_stride..(y_stride + image_width)];</span>
<span class="line" id="L693"> <span class="tok-kw">try</span> rle_encoder.encode(writer, pixel_stride);</span>
<span class="line" id="L694"> <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, <span class="tok-number">0x00</span>);</span>
<span class="line" id="L695"> }</span>
<span class="line" id="L696"></span>
<span class="line" id="L697"> <span class="tok-kw">try</span> rle_encoder.flush(writer);</span>
<span class="line" id="L698"> }</span>
<span class="line" id="L699"></span>
<span class="line" id="L700"> <span class="tok-kw">fn</span> <span class="tok-fn">writeRgb24</span>(self: *<span class="tok-kw">const</span> PCX, writer: buffered_stream_source.DefaultBufferedStreamSourceWriter.Writer, pixels: []<span class="tok-kw">const</span> color.Rgb24) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L701"> <span class="tok-kw">var</span> rle_encoder = RLEStreamEncoder{};</span>
<span class="line" id="L702"></span>
<span class="line" id="L703"> <span class="tok-kw">const</span> image_width = self.width();</span>
<span class="line" id="L704"> <span class="tok-kw">const</span> image_height = self.height();</span>
<span class="line" id="L705"></span>
<span class="line" id="L706"> <span class="tok-kw">const</span> is_even = ((image_width &amp; <span class="tok-number">0x1</span>) == <span class="tok-number">0</span>);</span>
<span class="line" id="L707"></span>
<span class="line" id="L708"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image_height) |y| {</span>
<span class="line" id="L709"> <span class="tok-kw">const</span> stride = y * image_width;</span>
<span class="line" id="L710"></span>
<span class="line" id="L711"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..<span class="tok-number">3</span>) |plane| {</span>
<span class="line" id="L712"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..image_width) |x| {</span>
<span class="line" id="L713"> <span class="tok-kw">const</span> current_color = pixels[stride + x];</span>
<span class="line" id="L714"> <span class="tok-kw">switch</span> (plane) {</span>
<span class="line" id="L715"> <span class="tok-number">0</span> =&gt; <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, current_color.r),</span>
<span class="line" id="L716"> <span class="tok-number">1</span> =&gt; <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, current_color.g),</span>
<span class="line" id="L717"> <span class="tok-number">2</span> =&gt; <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, current_color.b),</span>
<span class="line" id="L718"> <span class="tok-kw">else</span> =&gt; {},</span>
<span class="line" id="L719"> }</span>
<span class="line" id="L720"> }</span>
<span class="line" id="L721"></span>
<span class="line" id="L722"> <span class="tok-kw">if</span> (!is_even) {</span>
<span class="line" id="L723"> <span class="tok-kw">try</span> rle_encoder.encodeByte(writer, <span class="tok-number">0x00</span>);</span>
<span class="line" id="L724"> }</span>
<span class="line" id="L725"> }</span>
<span class="line" id="L726"> }</span>
<span class="line" id="L727"></span>
<span class="line" id="L728"> <span class="tok-kw">try</span> rle_encoder.flush(writer);</span>
<span class="line" id="L729"> }</span>
<span class="line" id="L730">};</span>
<span class="line" id="L731"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,351 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/png.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Implement PNG image format according to W3C Portable Network Graphics (PNG) specification second edition (ISO/IEC 15948:2003 (E))</span>
</span>
<span class="line" id="L2"><span class="tok-comment">// Last version: https://www.w3.org/TR/PNG/</span>
</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> chunk_writer = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;png/chunk_writer.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../color.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> filter = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;png/filtering.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L11"><span class="tok-kw">const</span> ImageWriteError = Image.WriteError;</span>
<span class="line" id="L12"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L13"><span class="tok-kw">const</span> reader = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;png/reader.zig&quot;</span>);</span>
<span class="line" id="L14"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L15"><span class="tok-kw">const</span> types = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;png/types.zig&quot;</span>);</span>
<span class="line" id="L16"><span class="tok-kw">const</span> ZlibCompressor = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;png/zlib_compressor.zig&quot;</span>).ZlibCompressor;</span>
<span class="line" id="L17"></span>
<span class="line" id="L18"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> HeaderData = types.HeaderData;</span>
<span class="line" id="L19"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ColorType = types.ColorType;</span>
<span class="line" id="L20"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CompressionMethod = types.CompressionMethod;</span>
<span class="line" id="L21"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FilterMethod = types.FilterMethod;</span>
<span class="line" id="L22"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FilterType = types.FilterType;</span>
<span class="line" id="L23"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> InterlaceMethod = types.InterlaceMethod;</span>
<span class="line" id="L24"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Chunks = types.Chunks;</span>
<span class="line" id="L25"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> isChunkCritical = reader.isChunkCritical;</span>
<span class="line" id="L26"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> load = reader.load;</span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> loadHeader = reader.loadHeader;</span>
<span class="line" id="L28"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> loadWithHeader = reader.loadWithHeader;</span>
<span class="line" id="L29"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ChunkProcessData = reader.ChunkProcessData;</span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PaletteProcessData = reader.PaletteProcessData;</span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> RowProcessData = reader.RowProcessData;</span>
<span class="line" id="L32"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ReaderProcessor = reader.ReaderProcessor;</span>
<span class="line" id="L33"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> TrnsProcessor = reader.TrnsProcessor;</span>
<span class="line" id="L34"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PlteProcessor = reader.PlteProcessor;</span>
<span class="line" id="L35"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ReaderOptions = reader.ReaderOptions;</span>
<span class="line" id="L36"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> DefaultProcessors = reader.DefaultProcessors;</span>
<span class="line" id="L37"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> DefaultOptions = reader.DefaultOptions;</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PNG = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L40"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L41"></span>
<span class="line" id="L42"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> EncoderOptions = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L43"> <span class="tok-comment">// For progressive rendering of big images</span>
</span>
<span class="line" id="L44"> interlaced: <span class="tok-type">bool</span> = <span class="tok-null">false</span>,</span>
<span class="line" id="L45"> <span class="tok-comment">// Changing this can affect performance positively or negatively</span>
</span>
<span class="line" id="L46"> filter_choice: filter.FilterChoice = .heuristic,</span>
<span class="line" id="L47"> };</span>
<span class="line" id="L48"></span>
<span class="line" id="L49"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatInterface</span>() FormatInterface {</span>
<span class="line" id="L50"> <span class="tok-kw">return</span> FormatInterface{</span>
<span class="line" id="L51"> .format = format,</span>
<span class="line" id="L52"> .formatDetect = formatDetect,</span>
<span class="line" id="L53"> .readImage = readImage,</span>
<span class="line" id="L54"> .writeImage = writeImage,</span>
<span class="line" id="L55"> };</span>
<span class="line" id="L56"> }</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">format</span>() Image.Format {</span>
<span class="line" id="L59"> <span class="tok-kw">return</span> Image.Format.png;</span>
<span class="line" id="L60"> }</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatDetect</span>(stream: *Image.Stream) ImageReadError!<span class="tok-type">bool</span> {</span>
<span class="line" id="L63"> <span class="tok-kw">var</span> magic_buffer: [types.magic_header.len]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> _ = <span class="tok-kw">try</span> stream.reader().readAll(magic_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L66"></span>
<span class="line" id="L67"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, magic_buffer[<span class="tok-number">0</span>..], types.magic_header[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readImage</span>(allocator: Allocator, stream: *Image.Stream) ImageReadError!Image {</span>
<span class="line" id="L71"> <span class="tok-kw">var</span> default_options = DefaultOptions{};</span>
<span class="line" id="L72"> <span class="tok-kw">return</span> load(stream, allocator, default_options.get());</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(allocator: Allocator, write_stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L76"> <span class="tok-kw">const</span> options = encoder_options.png;</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> <span class="tok-kw">try</span> ensureWritable(image);</span>
<span class="line" id="L79"></span>
<span class="line" id="L80"> <span class="tok-kw">const</span> header = HeaderData{</span>
<span class="line" id="L81"> .width = <span class="tok-builtin">@truncate</span>(image.width),</span>
<span class="line" id="L82"> .height = <span class="tok-builtin">@truncate</span>(image.height),</span>
<span class="line" id="L83"> .bit_depth = image.pixelFormat().bitsPerChannel(),</span>
<span class="line" id="L84"> .color_type = <span class="tok-kw">try</span> types.ColorType.fromPixelFormat(image.pixelFormat()),</span>
<span class="line" id="L85"> .compression_method = .deflate,</span>
<span class="line" id="L86"> .filter_method = .adaptive,</span>
<span class="line" id="L87"> .interlace_method = <span class="tok-kw">if</span> (options.interlaced) .adam7 <span class="tok-kw">else</span> .none,</span>
<span class="line" id="L88"> };</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> std.debug.assert(header.isValid());</span>
<span class="line" id="L91"></span>
<span class="line" id="L92"> <span class="tok-kw">try</span> write(allocator, write_stream, image.pixels, header, options.filter_choice);</span>
<span class="line" id="L93"> }</span>
<span class="line" id="L94"></span>
<span class="line" id="L95"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(allocator: Allocator, write_stream: *Image.Stream, pixels: color.PixelStorage, header: HeaderData, filter_choice: filter.FilterChoice) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L96"> <span class="tok-kw">if</span> (header.interlace_method != .none)</span>
<span class="line" id="L97"> <span class="tok-kw">return</span> ImageWriteError.Unsupported;</span>
<span class="line" id="L98"> <span class="tok-kw">if</span> (header.compression_method != .deflate)</span>
<span class="line" id="L99"> <span class="tok-kw">return</span> ImageWriteError.Unsupported;</span>
<span class="line" id="L100"> <span class="tok-kw">if</span> (header.filter_method != .adaptive)</span>
<span class="line" id="L101"> <span class="tok-kw">return</span> ImageWriteError.Unsupported;</span>
<span class="line" id="L102"></span>
<span class="line" id="L103"> <span class="tok-kw">const</span> writer = write_stream.writer();</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"> <span class="tok-kw">try</span> writeSignature(writer);</span>
<span class="line" id="L106"> <span class="tok-kw">try</span> writeHeader(writer, header);</span>
<span class="line" id="L107"> <span class="tok-kw">if</span> (PixelFormat.isIndexed(pixels)) {</span>
<span class="line" id="L108"> <span class="tok-kw">try</span> writePalette(writer, pixels);</span>
<span class="line" id="L109"> <span class="tok-kw">try</span> writeTransparencyInfo(writer, pixels); <span class="tok-comment">// TODO: pixel format where there is no transparency</span>
</span>
<span class="line" id="L110"> }</span>
<span class="line" id="L111"> <span class="tok-kw">try</span> writeData(allocator, writer, pixels, header, filter_choice);</span>
<span class="line" id="L112"> <span class="tok-kw">try</span> writeTrailer(writer);</span>
<span class="line" id="L113"> }</span>
<span class="line" id="L114"></span>
<span class="line" id="L115"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">ensureWritable</span>(image: Image) !<span class="tok-type">void</span> {</span>
<span class="line" id="L116"> <span class="tok-kw">if</span> (image.width &gt; std.math.maxInt(<span class="tok-type">u31</span>))</span>
<span class="line" id="L117"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unsupported;</span>
<span class="line" id="L118"> <span class="tok-kw">if</span> (image.height &gt; std.math.maxInt(<span class="tok-type">u31</span>))</span>
<span class="line" id="L119"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unsupported;</span>
<span class="line" id="L120"></span>
<span class="line" id="L121"> <span class="tok-kw">switch</span> (image.pixels) {</span>
<span class="line" id="L122"> .rgb24, .rgb48, .rgba32, .rgba64, .grayscale8, .grayscale16, .grayscale8Alpha, .grayscale16Alpha, .indexed8 =&gt; {},</span>
<span class="line" id="L123"></span>
<span class="line" id="L124"> .grayscale1, .grayscale2, .grayscale4, .indexed1, .indexed2, .indexed4 =&gt; <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unsupported, <span class="tok-comment">// TODO</span>
</span>
<span class="line" id="L125"></span>
<span class="line" id="L126"> <span class="tok-comment">// Should bgr be supported with swapping operations during the filtering?</span>
</span>
<span class="line" id="L127"></span>
<span class="line" id="L128"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unsupported,</span>
<span class="line" id="L129"> }</span>
<span class="line" id="L130"> }</span>
<span class="line" id="L131"></span>
<span class="line" id="L132"> <span class="tok-kw">fn</span> <span class="tok-fn">writeSignature</span>(writer: <span class="tok-kw">anytype</span>) !<span class="tok-type">void</span> {</span>
<span class="line" id="L133"> <span class="tok-kw">try</span> writer.writeAll(types.magic_header);</span>
<span class="line" id="L134"> }</span>
<span class="line" id="L135"></span>
<span class="line" id="L136"> <span class="tok-comment">// IHDR</span>
</span>
<span class="line" id="L137"> <span class="tok-kw">fn</span> <span class="tok-fn">writeHeader</span>(writer: <span class="tok-kw">anytype</span>, header: HeaderData) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L138"> <span class="tok-kw">var</span> chunk = chunk_writer.chunkWriter(writer, <span class="tok-str">&quot;IHDR&quot;</span>);</span>
<span class="line" id="L139"> <span class="tok-kw">var</span> chunk_wr = chunk.writer();</span>
<span class="line" id="L140"></span>
<span class="line" id="L141"> <span class="tok-kw">try</span> chunk_wr.writeInt(<span class="tok-type">u32</span>, header.width, .big);</span>
<span class="line" id="L142"> <span class="tok-kw">try</span> chunk_wr.writeInt(<span class="tok-type">u32</span>, header.height, .big);</span>
<span class="line" id="L143"> <span class="tok-kw">try</span> chunk_wr.writeInt(<span class="tok-type">u8</span>, header.bit_depth, .big);</span>
<span class="line" id="L144"> <span class="tok-kw">try</span> chunk_wr.writeInt(<span class="tok-type">u8</span>, <span class="tok-builtin">@intFromEnum</span>(header.color_type), .big);</span>
<span class="line" id="L145"> <span class="tok-kw">try</span> chunk_wr.writeInt(<span class="tok-type">u8</span>, <span class="tok-builtin">@intFromEnum</span>(header.compression_method), .big);</span>
<span class="line" id="L146"> <span class="tok-kw">try</span> chunk_wr.writeInt(<span class="tok-type">u8</span>, <span class="tok-builtin">@intFromEnum</span>(header.filter_method), .big);</span>
<span class="line" id="L147"> <span class="tok-kw">try</span> chunk_wr.writeInt(<span class="tok-type">u8</span>, <span class="tok-builtin">@intFromEnum</span>(header.interlace_method), .big);</span>
<span class="line" id="L148"></span>
<span class="line" id="L149"> <span class="tok-kw">try</span> chunk.flush();</span>
<span class="line" id="L150"> }</span>
<span class="line" id="L151"></span>
<span class="line" id="L152"> <span class="tok-comment">// IDAT (multiple maybe)</span>
</span>
<span class="line" id="L153"> <span class="tok-kw">fn</span> <span class="tok-fn">writeData</span>(allocator: Allocator, writer: <span class="tok-kw">anytype</span>, pixels: color.PixelStorage, header: HeaderData, filter_choice: filter.FilterChoice) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L154"> <span class="tok-comment">// Note: there may be more than 1 chunk</span>
</span>
<span class="line" id="L155"> <span class="tok-comment">// TODO: provide choice of how much it buffers (how much data per idat chunk)</span>
</span>
<span class="line" id="L156"> <span class="tok-kw">var</span> chunks = chunk_writer.chunkWriter(writer, <span class="tok-str">&quot;IDAT&quot;</span>);</span>
<span class="line" id="L157"> <span class="tok-kw">const</span> chunk_wr = chunks.writer();</span>
<span class="line" id="L158"></span>
<span class="line" id="L159"> <span class="tok-kw">var</span> zlib: ZlibCompressor(<span class="tok-builtin">@TypeOf</span>(chunk_wr)) = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L160"> <span class="tok-kw">try</span> zlib.init(allocator, chunk_wr);</span>
<span class="line" id="L161"></span>
<span class="line" id="L162"> <span class="tok-kw">try</span> zlib.begin();</span>
<span class="line" id="L163"> <span class="tok-kw">try</span> filter.filter(zlib.writer(), pixels, filter_choice, header);</span>
<span class="line" id="L164"> <span class="tok-kw">try</span> zlib.end();</span>
<span class="line" id="L165"></span>
<span class="line" id="L166"> <span class="tok-kw">try</span> chunks.flush();</span>
<span class="line" id="L167"> }</span>
<span class="line" id="L168"></span>
<span class="line" id="L169"> <span class="tok-comment">// IEND chunk</span>
</span>
<span class="line" id="L170"> <span class="tok-kw">fn</span> <span class="tok-fn">writeTrailer</span>(writer: <span class="tok-kw">anytype</span>) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L171"> <span class="tok-kw">var</span> chunk = chunk_writer.chunkWriter(writer, <span class="tok-str">&quot;IEND&quot;</span>);</span>
<span class="line" id="L172"> <span class="tok-kw">try</span> chunk.flush();</span>
<span class="line" id="L173"> }</span>
<span class="line" id="L174"></span>
<span class="line" id="L175"> <span class="tok-comment">// PLTE (if indexed storage)</span>
</span>
<span class="line" id="L176"> <span class="tok-kw">fn</span> <span class="tok-fn">writePalette</span>(writer: <span class="tok-kw">anytype</span>, pixels: color.PixelStorage) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L177"> <span class="tok-kw">var</span> chunk = chunk_writer.chunkWriter(writer, <span class="tok-str">&quot;PLTE&quot;</span>);</span>
<span class="line" id="L178"> <span class="tok-kw">var</span> chunk_wr = chunk.writer();</span>
<span class="line" id="L179"></span>
<span class="line" id="L180"> <span class="tok-kw">const</span> palette = <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L181"> .indexed1 =&gt; |d| d.palette,</span>
<span class="line" id="L182"> .indexed2 =&gt; |d| d.palette,</span>
<span class="line" id="L183"> .indexed4 =&gt; |d| d.palette,</span>
<span class="line" id="L184"> .indexed8 =&gt; |d| d.palette,</span>
<span class="line" id="L185"> .indexed16 =&gt; <span class="tok-kw">return</span> ImageWriteError.Unsupported,</span>
<span class="line" id="L186"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L187"> };</span>
<span class="line" id="L188"></span>
<span class="line" id="L189"> <span class="tok-kw">for</span> (palette) |col| {</span>
<span class="line" id="L190"> <span class="tok-kw">try</span> chunk_wr.writeByte(col.r);</span>
<span class="line" id="L191"> <span class="tok-kw">try</span> chunk_wr.writeByte(col.g);</span>
<span class="line" id="L192"> <span class="tok-kw">try</span> chunk_wr.writeByte(col.b);</span>
<span class="line" id="L193"> }</span>
<span class="line" id="L194"></span>
<span class="line" id="L195"> <span class="tok-kw">try</span> chunk.flush();</span>
<span class="line" id="L196"> }</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-comment">// tRNS (if indexed storage with transparency (there may be other uses later))</span>
</span>
<span class="line" id="L199"> <span class="tok-kw">fn</span> <span class="tok-fn">writeTransparencyInfo</span>(writer: <span class="tok-kw">anytype</span>, pixels: color.PixelStorage) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L200"> <span class="tok-kw">var</span> chunk = chunk_writer.chunkWriter(writer, <span class="tok-str">&quot;tRNS&quot;</span>);</span>
<span class="line" id="L201"> <span class="tok-kw">var</span> chunk_wr = chunk.writer();</span>
<span class="line" id="L202"></span>
<span class="line" id="L203"> <span class="tok-kw">const</span> palette = <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L204"> .indexed1 =&gt; |d| d.palette,</span>
<span class="line" id="L205"> .indexed2 =&gt; |d| d.palette,</span>
<span class="line" id="L206"> .indexed4 =&gt; |d| d.palette,</span>
<span class="line" id="L207"> .indexed8 =&gt; |d| d.palette,</span>
<span class="line" id="L208"> .indexed16 =&gt; <span class="tok-kw">return</span> ImageWriteError.Unsupported,</span>
<span class="line" id="L209"> <span class="tok-comment">// TODO: png support transparency info for other formats?</span>
</span>
<span class="line" id="L210"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L211"> };</span>
<span class="line" id="L212"></span>
<span class="line" id="L213"> <span class="tok-kw">for</span> (palette) |col| {</span>
<span class="line" id="L214"> <span class="tok-kw">try</span> chunk_wr.writeByte(col.a);</span>
<span class="line" id="L215"> }</span>
<span class="line" id="L216"></span>
<span class="line" id="L217"> <span class="tok-kw">try</span> chunk.flush();</span>
<span class="line" id="L218"> }</span>
<span class="line" id="L219">};</span>
<span class="line" id="L220"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,182 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/png/chunk_writer.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> io = std.io;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> mem = std.mem;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> Crc = std.hash.crc.Crc32WithPoly(.IEEE);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-comment">/// Writer based on buffered writer that will write whole chunks of data of [buffer size]</span></span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">ChunkWriter</span>(<span class="tok-kw">comptime</span> buffer_size: <span class="tok-type">usize</span>, <span class="tok-kw">comptime</span> WriterType: <span class="tok-type">type</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L10"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L11"> unbuffered_writer: WriterType,</span>
<span class="line" id="L12"> buf: [buffer_size]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L13"> end: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L14"> section_id: [<span class="tok-number">4</span>]<span class="tok-type">u8</span>,</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Error = WriterType.Error;</span>
<span class="line" id="L17"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Writer = io.Writer(*Self, Error, write);</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">flush</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L22"> <span class="tok-kw">try</span> self.unbuffered_writer.writeInt(<span class="tok-type">u32</span>, <span class="tok-builtin">@as</span>(<span class="tok-type">u32</span>, <span class="tok-builtin">@truncate</span>(self.end)), .big);</span>
<span class="line" id="L23"></span>
<span class="line" id="L24"> <span class="tok-kw">var</span> crc = Crc.init();</span>
<span class="line" id="L25"></span>
<span class="line" id="L26"> crc.update(&amp;self.section_id);</span>
<span class="line" id="L27"> <span class="tok-kw">try</span> self.unbuffered_writer.writeAll(&amp;self.section_id);</span>
<span class="line" id="L28"> crc.update(self.buf[<span class="tok-number">0</span>..self.end]);</span>
<span class="line" id="L29"> <span class="tok-kw">try</span> self.unbuffered_writer.writeAll(self.buf[<span class="tok-number">0</span>..self.end]);</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"> <span class="tok-kw">try</span> self.unbuffered_writer.writeInt(<span class="tok-type">u32</span>, crc.final(), .big);</span>
<span class="line" id="L32"></span>
<span class="line" id="L33"> self.end = <span class="tok-number">0</span>;</span>
<span class="line" id="L34"> }</span>
<span class="line" id="L35"></span>
<span class="line" id="L36"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writer</span>(self: *Self) Writer {</span>
<span class="line" id="L37"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L38"> }</span>
<span class="line" id="L39"></span>
<span class="line" id="L40"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: *Self, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) Error!<span class="tok-type">usize</span> {</span>
<span class="line" id="L41"> <span class="tok-kw">if</span> (self.end + bytes.len &gt; self.buf.len) {</span>
<span class="line" id="L42"> <span class="tok-kw">try</span> self.flush();</span>
<span class="line" id="L43"> <span class="tok-kw">if</span> (bytes.len &gt; self.buf.len)</span>
<span class="line" id="L44"> <span class="tok-kw">return</span> self.unbuffered_writer.write(bytes);</span>
<span class="line" id="L45"> }</span>
<span class="line" id="L46"></span>
<span class="line" id="L47"> <span class="tok-builtin">@memcpy</span>(self.buf[self.end..][<span class="tok-number">0</span>..bytes.len], bytes);</span>
<span class="line" id="L48"> self.end += bytes.len;</span>
<span class="line" id="L49"> <span class="tok-kw">return</span> bytes.len;</span>
<span class="line" id="L50"> }</span>
<span class="line" id="L51"> };</span>
<span class="line" id="L52">}</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"><span class="tok-kw">const</span> ChunkBufferSize = <span class="tok-number">1</span> &lt;&lt; <span class="tok-number">14</span>; <span class="tok-comment">// 16 kb</span>
</span>
<span class="line" id="L55"></span>
<span class="line" id="L56"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">chunkWriter</span>(underlying_stream: <span class="tok-kw">anytype</span>, <span class="tok-kw">comptime</span> id: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ChunkWriter(ChunkBufferSize, <span class="tok-builtin">@TypeOf</span>(underlying_stream)) {</span>
<span class="line" id="L57"> <span class="tok-kw">if</span> (id.len != <span class="tok-number">4</span>)</span>
<span class="line" id="L58"> <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;PNG chunk id must be 4 characters&quot;</span>);</span>
<span class="line" id="L59"></span>
<span class="line" id="L60"> <span class="tok-kw">return</span> .{ .unbuffered_writer = underlying_stream, .section_id = std.mem.bytesToValue([<span class="tok-number">4</span>]<span class="tok-type">u8</span>, id[<span class="tok-number">0</span>..<span class="tok-number">4</span>]) };</span>
<span class="line" id="L61">}</span>
<span class="line" id="L62"></span>
<span class="line" id="L63"><span class="tok-comment">// TODO: test idat writer</span>
</span>
<span class="line" id="L64"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,320 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/png/filtering.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../color.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../Image.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> HeaderData = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;types.zig&quot;</span>).HeaderData;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> builtin = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;builtin&quot;</span>);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FilterType = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L9"> none = <span class="tok-number">0</span>,</span>
<span class="line" id="L10"> sub = <span class="tok-number">1</span>,</span>
<span class="line" id="L11"> up = <span class="tok-number">2</span>,</span>
<span class="line" id="L12"> average = <span class="tok-number">3</span>,</span>
<span class="line" id="L13"> paeth = <span class="tok-number">4</span>,</span>
<span class="line" id="L14">};</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FilterChoiceStrategies = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L17"> try_all,</span>
<span class="line" id="L18"> heuristic,</span>
<span class="line" id="L19"> specified,</span>
<span class="line" id="L20">};</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FilterChoice = <span class="tok-kw">union</span>(FilterChoiceStrategies) {</span>
<span class="line" id="L23"> try_all,</span>
<span class="line" id="L24"> heuristic,</span>
<span class="line" id="L25"> specified: FilterType,</span>
<span class="line" id="L26">};</span>
<span class="line" id="L27"></span>
<span class="line" id="L28"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">filter</span>(writer: <span class="tok-kw">anytype</span>, pixels: color.PixelStorage, filter_choice: FilterChoice, header: HeaderData) Image.WriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L29"> <span class="tok-kw">var</span> scanline: color.PixelStorage = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L30"> <span class="tok-kw">var</span> previous_scanline: ?color.PixelStorage = <span class="tok-null">null</span>;</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"> <span class="tok-kw">const</span> format: PixelFormat = pixels;</span>
<span class="line" id="L33"></span>
<span class="line" id="L34"> <span class="tok-kw">if</span> (format.bitsPerChannel() &lt; <span class="tok-number">8</span>)</span>
<span class="line" id="L35"> <span class="tok-kw">return</span> Image.WriteError.Unsupported;</span>
<span class="line" id="L36"></span>
<span class="line" id="L37"> <span class="tok-kw">const</span> pixel_len = format.pixelStride();</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"> <span class="tok-kw">var</span> y: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L40"> <span class="tok-kw">while</span> (y &lt; header.height) : (y += <span class="tok-number">1</span>) {</span>
<span class="line" id="L41"> scanline = pixels.slice(y * header.width, (y + <span class="tok-number">1</span>) * header.width);</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"> <span class="tok-kw">const</span> filter_type: FilterType = <span class="tok-kw">switch</span> (filter_choice) {</span>
<span class="line" id="L44"> .try_all =&gt; <span class="tok-builtin">@panic</span>(<span class="tok-str">&quot;Unimplemented&quot;</span>),</span>
<span class="line" id="L45"> .heuristic =&gt; filterChoiceHeuristic(scanline, previous_scanline),</span>
<span class="line" id="L46"> .specified =&gt; |f| f,</span>
<span class="line" id="L47"> };</span>
<span class="line" id="L48"></span>
<span class="line" id="L49"> <span class="tok-kw">try</span> writer.writeByte(<span class="tok-builtin">@intFromEnum</span>(filter_type));</span>
<span class="line" id="L50"></span>
<span class="line" id="L51"> <span class="tok-kw">for</span> (<span class="tok-number">0</span>..scanline.asBytes().len) |byte_index| {</span>
<span class="line" id="L52"> <span class="tok-kw">const</span> i = <span class="tok-kw">if</span> (builtin.target.cpu.arch.endian() == .little) pixelByteSwappedIndex(scanline, byte_index) <span class="tok-kw">else</span> byte_index;</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-kw">const</span> sample = scanline.asBytes()[i];</span>
<span class="line" id="L55"> <span class="tok-kw">const</span> previous: <span class="tok-type">u8</span> = <span class="tok-kw">if</span> (byte_index &gt;= pixel_len) scanline.asBytes()[i - pixel_len] <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L56"> <span class="tok-kw">const</span> above: <span class="tok-type">u8</span> = <span class="tok-kw">if</span> (previous_scanline) |b| b.asBytes()[i] <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L57"> <span class="tok-kw">const</span> above_previous = <span class="tok-kw">if</span> (previous_scanline) |b| (<span class="tok-kw">if</span> (byte_index &gt;= pixel_len) b.asBytes()[i - pixel_len] <span class="tok-kw">else</span> <span class="tok-number">0</span>) <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L58"></span>
<span class="line" id="L59"> <span class="tok-kw">const</span> byte: <span class="tok-type">u8</span> = <span class="tok-kw">switch</span> (filter_type) {</span>
<span class="line" id="L60"> .none =&gt; sample,</span>
<span class="line" id="L61"> .sub =&gt; sample -% previous,</span>
<span class="line" id="L62"> .up =&gt; sample -% above,</span>
<span class="line" id="L63"> .average =&gt; sample -% average(previous, above),</span>
<span class="line" id="L64"> .paeth =&gt; sample -% paeth(previous, above, above_previous),</span>
<span class="line" id="L65"> };</span>
<span class="line" id="L66"></span>
<span class="line" id="L67"> <span class="tok-kw">try</span> writer.writeByte(byte);</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"> previous_scanline = scanline;</span>
<span class="line" id="L70"> }</span>
<span class="line" id="L71">}</span>
<span class="line" id="L72"></span>
<span class="line" id="L73"><span class="tok-comment">// Map the index of a byte to what it would be if each struct element was byte swapped</span>
</span>
<span class="line" id="L74"><span class="tok-kw">fn</span> <span class="tok-fn">pixelByteSwappedIndex</span>(storage: color.PixelStorage, index: <span class="tok-type">usize</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L75"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (storage) {</span>
<span class="line" id="L76"> .invalid =&gt; index,</span>
<span class="line" id="L77"> <span class="tok-kw">inline</span> .indexed1, .indexed2, .indexed4, .indexed8, .indexed16 =&gt; |data| byteSwappedIndex(<span class="tok-builtin">@typeInfo</span>(<span class="tok-builtin">@TypeOf</span>(data.indices)).Pointer.child, index),</span>
<span class="line" id="L78"> <span class="tok-kw">inline</span> <span class="tok-kw">else</span> =&gt; |data| byteSwappedIndex(<span class="tok-builtin">@typeInfo</span>(<span class="tok-builtin">@TypeOf</span>(data)).Pointer.child, index),</span>
<span class="line" id="L79"> };</span>
<span class="line" id="L80">}</span>
<span class="line" id="L81"></span>
<span class="line" id="L82"><span class="tok-comment">// Map the index of a byte to what it would be if each struct element was byte swapped</span>
</span>
<span class="line" id="L83"><span class="tok-kw">fn</span> <span class="tok-fn">byteSwappedIndex</span>(<span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>, byte_index: <span class="tok-type">usize</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L84"> <span class="tok-kw">const</span> element_index = byte_index / <span class="tok-builtin">@sizeOf</span>(T);</span>
<span class="line" id="L85"> <span class="tok-kw">const</span> element_offset = element_index * <span class="tok-builtin">@sizeOf</span>(T);</span>
<span class="line" id="L86"> <span class="tok-kw">const</span> index = byte_index % <span class="tok-builtin">@sizeOf</span>(T);</span>
<span class="line" id="L87"> <span class="tok-kw">switch</span> (<span class="tok-builtin">@typeInfo</span>(T)) {</span>
<span class="line" id="L88"> .Int =&gt; {</span>
<span class="line" id="L89"> <span class="tok-kw">if</span> (<span class="tok-builtin">@sizeOf</span>(T) == <span class="tok-number">1</span>) <span class="tok-kw">return</span> byte_index;</span>
<span class="line" id="L90"> <span class="tok-kw">return</span> element_offset + <span class="tok-builtin">@sizeOf</span>(T) - <span class="tok-number">1</span> - index;</span>
<span class="line" id="L91"> },</span>
<span class="line" id="L92"> .Struct =&gt; |info| {</span>
<span class="line" id="L93"> <span class="tok-kw">inline</span> <span class="tok-kw">for</span> (info.fields) |field| {</span>
<span class="line" id="L94"> <span class="tok-kw">if</span> (index &gt;= <span class="tok-builtin">@offsetOf</span>(T, field.name) <span class="tok-kw">or</span> index &lt;= <span class="tok-builtin">@offsetOf</span>(T, field.name) + <span class="tok-builtin">@sizeOf</span>(field.<span class="tok-type">type</span>)) {</span>
<span class="line" id="L95"> <span class="tok-kw">if</span> (<span class="tok-builtin">@sizeOf</span>(field.<span class="tok-type">type</span>) == <span class="tok-number">1</span>) <span class="tok-kw">return</span> byte_index;</span>
<span class="line" id="L96"> <span class="tok-kw">return</span> element_offset + <span class="tok-builtin">@sizeOf</span>(field.<span class="tok-type">type</span>) - <span class="tok-number">1</span> - index;</span>
<span class="line" id="L97"> }</span>
<span class="line" id="L98"> }</span>
<span class="line" id="L99"> },</span>
<span class="line" id="L100"> <span class="tok-kw">else</span> =&gt; <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;type &quot;</span> ++ <span class="tok-builtin">@typeName</span>(T) ++ <span class="tok-str">&quot; not supported&quot;</span>),</span>
<span class="line" id="L101"> }</span>
<span class="line" id="L102">}</span>
<span class="line" id="L103"></span>
<span class="line" id="L104"><span class="tok-kw">fn</span> <span class="tok-fn">filterChoiceHeuristic</span>(scanline: color.PixelStorage, previous_scanline: ?color.PixelStorage) FilterType {</span>
<span class="line" id="L105"> <span class="tok-kw">const</span> pixel_len = <span class="tok-builtin">@as</span>(PixelFormat, scanline).pixelStride();</span>
<span class="line" id="L106"></span>
<span class="line" id="L107"> <span class="tok-kw">const</span> filter_types = [_]FilterType{ .none, .sub, .up, .average, .paeth };</span>
<span class="line" id="L108"></span>
<span class="line" id="L109"> <span class="tok-kw">var</span> previous_bytes: [filter_types.len]<span class="tok-type">u8</span> = [_]<span class="tok-type">u8</span>{<span class="tok-number">0</span>} ** filter_types.len;</span>
<span class="line" id="L110"> <span class="tok-kw">var</span> combos: [filter_types.len]<span class="tok-type">usize</span> = [_]<span class="tok-type">usize</span>{<span class="tok-number">0</span>} ** filter_types.len;</span>
<span class="line" id="L111"> <span class="tok-kw">var</span> scores: [filter_types.len]<span class="tok-type">usize</span> = [_]<span class="tok-type">usize</span>{<span class="tok-number">0</span>} ** filter_types.len;</span>
<span class="line" id="L112"></span>
<span class="line" id="L113"> <span class="tok-kw">for</span> (scanline.asBytes(), <span class="tok-number">0</span>..) |sample, i| {</span>
<span class="line" id="L114"> <span class="tok-kw">const</span> previous: <span class="tok-type">u8</span> = <span class="tok-kw">if</span> (i &gt;= pixel_len) scanline.asBytes()[i - pixel_len] <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L115"> <span class="tok-kw">const</span> above: <span class="tok-type">u8</span> = <span class="tok-kw">if</span> (previous_scanline) |b| b.asBytes()[i] <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L116"> <span class="tok-kw">const</span> above_previous = <span class="tok-kw">if</span> (previous_scanline) |b| (<span class="tok-kw">if</span> (i &gt;= pixel_len) b.asBytes()[i - pixel_len] <span class="tok-kw">else</span> <span class="tok-number">0</span>) <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"> <span class="tok-kw">inline</span> <span class="tok-kw">for</span> (filter_types, &amp;previous_bytes, &amp;combos, &amp;scores) |filter_type, *previous_byte, *combo, *score| {</span>
<span class="line" id="L119"> <span class="tok-kw">const</span> byte: <span class="tok-type">u8</span> = <span class="tok-kw">switch</span> (filter_type) {</span>
<span class="line" id="L120"> .none =&gt; sample,</span>
<span class="line" id="L121"> .sub =&gt; sample -% previous,</span>
<span class="line" id="L122"> .up =&gt; sample -% above,</span>
<span class="line" id="L123"> .average =&gt; sample -% average(previous, above),</span>
<span class="line" id="L124"> .paeth =&gt; sample -% paeth(previous, above, above_previous),</span>
<span class="line" id="L125"> };</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"> <span class="tok-kw">if</span> (byte == previous_byte.*) {</span>
<span class="line" id="L128"> combo.* += <span class="tok-number">1</span>;</span>
<span class="line" id="L129"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L130"> score.* += combo.* * combo.*;</span>
<span class="line" id="L131"> combo.* = <span class="tok-number">0</span>;</span>
<span class="line" id="L132"> previous_byte.* = byte;</span>
<span class="line" id="L133"> }</span>
<span class="line" id="L134"> }</span>
<span class="line" id="L135"> }</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"> <span class="tok-kw">var</span> best: FilterType = .none;</span>
<span class="line" id="L138"> <span class="tok-kw">var</span> max_score: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L139"> <span class="tok-kw">inline</span> <span class="tok-kw">for</span> (filter_types, scores) |filter_type, score| {</span>
<span class="line" id="L140"> <span class="tok-kw">if</span> (score &gt; max_score) {</span>
<span class="line" id="L141"> max_score = score;</span>
<span class="line" id="L142"> best = filter_type;</span>
<span class="line" id="L143"> }</span>
<span class="line" id="L144"> }</span>
<span class="line" id="L145"> <span class="tok-kw">return</span> best;</span>
<span class="line" id="L146">}</span>
<span class="line" id="L147"></span>
<span class="line" id="L148"><span class="tok-kw">fn</span> <span class="tok-fn">average</span>(a: <span class="tok-type">u9</span>, b: <span class="tok-type">u9</span>) <span class="tok-type">u8</span> {</span>
<span class="line" id="L149"> <span class="tok-kw">return</span> <span class="tok-builtin">@truncate</span>((a + b) / <span class="tok-number">2</span>);</span>
<span class="line" id="L150">}</span>
<span class="line" id="L151"></span>
<span class="line" id="L152"><span class="tok-kw">fn</span> <span class="tok-fn">paeth</span>(b4: <span class="tok-type">u8</span>, up: <span class="tok-type">u8</span>, b4_up: <span class="tok-type">u8</span>) <span class="tok-type">u8</span> {</span>
<span class="line" id="L153"> <span class="tok-kw">const</span> p: <span class="tok-type">i16</span> = <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, <span class="tok-builtin">@intCast</span>(b4)) + up - b4_up;</span>
<span class="line" id="L154"> <span class="tok-kw">const</span> pa = <span class="tok-builtin">@abs</span>(p - b4);</span>
<span class="line" id="L155"> <span class="tok-kw">const</span> pb = <span class="tok-builtin">@abs</span>(p - up);</span>
<span class="line" id="L156"> <span class="tok-kw">const</span> pc = <span class="tok-builtin">@abs</span>(p - b4_up);</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"> <span class="tok-kw">if</span> (pa &lt;= pb <span class="tok-kw">and</span> pa &lt;= pc) {</span>
<span class="line" id="L159"> <span class="tok-kw">return</span> b4;</span>
<span class="line" id="L160"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (pb &lt;= pc) {</span>
<span class="line" id="L161"> <span class="tok-kw">return</span> up;</span>
<span class="line" id="L162"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L163"> <span class="tok-kw">return</span> b4_up;</span>
<span class="line" id="L164"> }</span>
<span class="line" id="L165">}</span>
<span class="line" id="L166"></span>
<span class="line" id="L167"><span class="tok-kw">test</span> <span class="tok-str">&quot;filtering 16-bit grayscale pixels uses correct endianess&quot;</span> {</span>
<span class="line" id="L168"> <span class="tok-kw">var</span> output_bytes = std.ArrayList(<span class="tok-type">u8</span>).init(std.testing.allocator);</span>
<span class="line" id="L169"> <span class="tok-kw">defer</span> output_bytes.deinit();</span>
<span class="line" id="L170"></span>
<span class="line" id="L171"> <span class="tok-kw">const</span> pixels = <span class="tok-kw">try</span> std.testing.allocator.dupe(color.Grayscale16, &amp;.{</span>
<span class="line" id="L172"> .{ .value = <span class="tok-number">0xF</span> },</span>
<span class="line" id="L173"> .{ .value = <span class="tok-number">0xFF</span> },</span>
<span class="line" id="L174"> .{ .value = <span class="tok-number">0xFFF</span> },</span>
<span class="line" id="L175"> .{ .value = <span class="tok-number">0xFFFF</span> },</span>
<span class="line" id="L176"> .{ .value = <span class="tok-number">0xF</span> },</span>
<span class="line" id="L177"> .{ .value = <span class="tok-number">0xFF</span> },</span>
<span class="line" id="L178"> .{ .value = <span class="tok-number">0xFFF</span> },</span>
<span class="line" id="L179"> .{ .value = <span class="tok-number">0xFFFF</span> },</span>
<span class="line" id="L180"> });</span>
<span class="line" id="L181"> <span class="tok-kw">defer</span> std.testing.allocator.free(pixels);</span>
<span class="line" id="L182"></span>
<span class="line" id="L183"> <span class="tok-comment">// We specify the endianess as none to simplify the test</span>
</span>
<span class="line" id="L184"> <span class="tok-kw">try</span> filter(output_bytes.writer(), .{ .grayscale16 = pixels }, .{ .specified = .none }, .{</span>
<span class="line" id="L185"> .width = <span class="tok-number">4</span>,</span>
<span class="line" id="L186"> .height = <span class="tok-number">2</span>,</span>
<span class="line" id="L187"> .bit_depth = <span class="tok-number">16</span>,</span>
<span class="line" id="L188"> .color_type = .grayscale,</span>
<span class="line" id="L189"> .compression_method = .deflate,</span>
<span class="line" id="L190"> .filter_method = .adaptive,</span>
<span class="line" id="L191"> .interlace_method = .none,</span>
<span class="line" id="L192"> });</span>
<span class="line" id="L193"></span>
<span class="line" id="L194"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, &amp;.{</span>
<span class="line" id="L195"> <span class="tok-number">0x00</span>, <span class="tok-number">0x00</span>, <span class="tok-number">0x0F</span>, <span class="tok-number">0x00</span>, <span class="tok-number">0xFF</span>, <span class="tok-number">0x0F</span>, <span class="tok-number">0xFF</span>, <span class="tok-number">0xFF</span>, <span class="tok-number">0xFF</span>, <span class="tok-comment">//</span>
</span>
<span class="line" id="L196"> <span class="tok-number">0x00</span>, <span class="tok-number">0x00</span>, <span class="tok-number">0x0F</span>, <span class="tok-number">0x00</span>, <span class="tok-number">0xFF</span>, <span class="tok-number">0x0F</span>, <span class="tok-number">0xFF</span>, <span class="tok-number">0xFF</span>, <span class="tok-number">0xFF</span>, <span class="tok-comment">//</span>
</span>
<span class="line" id="L197"> }, output_bytes.items);</span>
<span class="line" id="L198">}</span>
<span class="line" id="L199"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,310 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/png/types.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> utils = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../utils.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../color.zig&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L6"><span class="tok-kw">const</span> Colorf32 = color.Colorf32;</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> magic_header = <span class="tok-str">&quot;\x89PNG\x0D\x0A\x1A\x0A&quot;</span>;</span>
<span class="line" id="L9"></span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Chunk = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L11"> id: <span class="tok-type">u32</span>,</span>
<span class="line" id="L12"> name: *<span class="tok-kw">const</span> [<span class="tok-number">4</span>:<span class="tok-number">0</span>]<span class="tok-type">u8</span>,</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(name: *<span class="tok-kw">const</span> [<span class="tok-number">4</span>:<span class="tok-number">0</span>]<span class="tok-type">u8</span>) Chunk {</span>
<span class="line" id="L15"> <span class="tok-kw">return</span> .{ .name = name, .id = std.mem.bigToNative(<span class="tok-type">u32</span>, std.mem.bytesToValue(<span class="tok-type">u32</span>, name)) };</span>
<span class="line" id="L16"> }</span>
<span class="line" id="L17">};</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Chunks = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L20"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> IHDR = Chunk.init(<span class="tok-str">&quot;IHDR&quot;</span>);</span>
<span class="line" id="L21"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> PLTE = Chunk.init(<span class="tok-str">&quot;PLTE&quot;</span>);</span>
<span class="line" id="L22"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> IDAT = Chunk.init(<span class="tok-str">&quot;IDAT&quot;</span>);</span>
<span class="line" id="L23"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> IEND = Chunk.init(<span class="tok-str">&quot;IEND&quot;</span>);</span>
<span class="line" id="L24"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> gAMA = Chunk.init(<span class="tok-str">&quot;gAMA&quot;</span>);</span>
<span class="line" id="L25"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> sBIT = Chunk.init(<span class="tok-str">&quot;sBIT&quot;</span>);</span>
<span class="line" id="L26"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> tEXt = Chunk.init(<span class="tok-str">&quot;tEXt&quot;</span>);</span>
<span class="line" id="L27"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> zTXt = Chunk.init(<span class="tok-str">&quot;zTXt&quot;</span>);</span>
<span class="line" id="L28"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> iTXt = Chunk.init(<span class="tok-str">&quot;iTXt&quot;</span>);</span>
<span class="line" id="L29"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> cHRM = Chunk.init(<span class="tok-str">&quot;cHRM&quot;</span>);</span>
<span class="line" id="L30"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> pHYs = Chunk.init(<span class="tok-str">&quot;pHYs&quot;</span>);</span>
<span class="line" id="L31"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> tRNS = Chunk.init(<span class="tok-str">&quot;tRNS&quot;</span>);</span>
<span class="line" id="L32"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> bKGD = Chunk.init(<span class="tok-str">&quot;bKGD&quot;</span>);</span>
<span class="line" id="L33"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> tIME = Chunk.init(<span class="tok-str">&quot;tIME&quot;</span>);</span>
<span class="line" id="L34"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> iCCP = Chunk.init(<span class="tok-str">&quot;iCCP&quot;</span>);</span>
<span class="line" id="L35"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> sRGB = Chunk.init(<span class="tok-str">&quot;sRGB&quot;</span>);</span>
<span class="line" id="L36"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Any = Chunk.init(<span class="tok-str">&quot;_ANY&quot;</span>);</span>
<span class="line" id="L37">};</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ColorType = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L40"> grayscale = <span class="tok-number">0</span>,</span>
<span class="line" id="L41"> rgb_color = <span class="tok-number">2</span>,</span>
<span class="line" id="L42"> indexed = <span class="tok-number">3</span>,</span>
<span class="line" id="L43"> grayscale_alpha = <span class="tok-number">4</span>,</span>
<span class="line" id="L44"> rgba_color = <span class="tok-number">6</span>,</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L47"></span>
<span class="line" id="L48"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">channelCount</span>(self: Self) <span class="tok-type">u8</span> {</span>
<span class="line" id="L49"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self) {</span>
<span class="line" id="L50"> .grayscale =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L51"> .rgb_color =&gt; <span class="tok-number">3</span>,</span>
<span class="line" id="L52"> .indexed =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L53"> .grayscale_alpha =&gt; <span class="tok-number">2</span>,</span>
<span class="line" id="L54"> .rgba_color =&gt; <span class="tok-number">4</span>,</span>
<span class="line" id="L55"> };</span>
<span class="line" id="L56"> }</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">fromPixelFormat</span>(pixel_format: PixelFormat) !Self {</span>
<span class="line" id="L59"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (pixel_format) {</span>
<span class="line" id="L60"> .rgb24, .rgb48 =&gt; .rgb_color,</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"> .rgba32, .rgba64 =&gt; .rgba_color,</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"> .grayscale1, .grayscale2, .grayscale4, .grayscale8, .grayscale16 =&gt; .grayscale,</span>
<span class="line" id="L65"></span>
<span class="line" id="L66"> .grayscale8Alpha, .grayscale16Alpha =&gt; .grayscale_alpha,</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"> .indexed1, .indexed2, .indexed4, .indexed8 =&gt; .indexed,</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> <span class="tok-kw">error</span>.Unsupported,</span>
<span class="line" id="L71"> };</span>
<span class="line" id="L72"> }</span>
<span class="line" id="L73">};</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FilterType = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L76"> none = <span class="tok-number">0</span>,</span>
<span class="line" id="L77"> sub = <span class="tok-number">1</span>,</span>
<span class="line" id="L78"> up = <span class="tok-number">2</span>,</span>
<span class="line" id="L79"> average = <span class="tok-number">3</span>,</span>
<span class="line" id="L80"> paeth = <span class="tok-number">4</span>,</span>
<span class="line" id="L81">};</span>
<span class="line" id="L82"></span>
<span class="line" id="L83"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> InterlaceMethod = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L84"> none = <span class="tok-number">0</span>,</span>
<span class="line" id="L85"> adam7 = <span class="tok-number">1</span>,</span>
<span class="line" id="L86">};</span>
<span class="line" id="L87"></span>
<span class="line" id="L88"><span class="tok-comment">/// The compression methods supported by PNG</span></span>
<span class="line" id="L89"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CompressionMethod = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) { deflate = <span class="tok-number">0</span>, _ };</span>
<span class="line" id="L90"></span>
<span class="line" id="L91"><span class="tok-comment">/// The filter methods supported by PNG</span></span>
<span class="line" id="L92"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FilterMethod = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) { adaptive = <span class="tok-number">0</span>, _ };</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ChunkHeader = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L95"> length: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L96"> <span class="tok-type">type</span>: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L97"></span>
<span class="line" id="L98"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L99"></span>
<span class="line" id="L100"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">name</span>(self: *Self) []<span class="tok-kw">const</span> <span class="tok-type">u8</span> {</span>
<span class="line" id="L101"> <span class="tok-kw">return</span> std.mem.asBytes(&amp;self.<span class="tok-type">type</span>);</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103">};</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> HeaderData = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L106"> width: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L107"> height: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L108"> bit_depth: <span class="tok-type">u8</span>,</span>
<span class="line" id="L109"> color_type: ColorType,</span>
<span class="line" id="L110"> compression_method: CompressionMethod,</span>
<span class="line" id="L111"> filter_method: FilterMethod,</span>
<span class="line" id="L112"> interlace_method: InterlaceMethod,</span>
<span class="line" id="L113"></span>
<span class="line" id="L114"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L115"></span>
<span class="line" id="L116"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isValid</span>(self: *<span class="tok-kw">const</span> Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L117"> <span class="tok-kw">const</span> max_dim = std.math.maxInt(<span class="tok-type">u32</span>) &gt;&gt; <span class="tok-number">1</span>;</span>
<span class="line" id="L118"> <span class="tok-kw">const</span> w = self.width;</span>
<span class="line" id="L119"> <span class="tok-kw">const</span> h = self.height;</span>
<span class="line" id="L120"> <span class="tok-kw">if</span> (w == <span class="tok-number">0</span> <span class="tok-kw">or</span> w &gt; max_dim) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L121"> <span class="tok-kw">if</span> (h == <span class="tok-number">0</span> <span class="tok-kw">or</span> h &gt; max_dim) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"> <span class="tok-kw">const</span> bd = self.bit_depth;</span>
<span class="line" id="L124"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.color_type) {</span>
<span class="line" id="L125"> .grayscale =&gt; bd == <span class="tok-number">1</span> <span class="tok-kw">or</span> bd == <span class="tok-number">2</span> <span class="tok-kw">or</span> bd == <span class="tok-number">4</span> <span class="tok-kw">or</span> bd == <span class="tok-number">8</span> <span class="tok-kw">or</span> bd == <span class="tok-number">16</span>,</span>
<span class="line" id="L126"> .indexed =&gt; bd == <span class="tok-number">1</span> <span class="tok-kw">or</span> bd == <span class="tok-number">2</span> <span class="tok-kw">or</span> bd == <span class="tok-number">4</span> <span class="tok-kw">or</span> bd == <span class="tok-number">8</span>,</span>
<span class="line" id="L127"> <span class="tok-kw">else</span> =&gt; bd == <span class="tok-number">8</span> <span class="tok-kw">or</span> bd == <span class="tok-number">16</span>,</span>
<span class="line" id="L128"> };</span>
<span class="line" id="L129"> }</span>
<span class="line" id="L130"></span>
<span class="line" id="L131"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">allowsPalette</span>(self: *<span class="tok-kw">const</span> Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L132"> <span class="tok-kw">return</span> self.color_type == .indexed <span class="tok-kw">or</span></span>
<span class="line" id="L133"> self.color_type == .rgb_color <span class="tok-kw">or</span></span>
<span class="line" id="L134"> self.color_type == .rgba_color;</span>
<span class="line" id="L135"> }</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">maxPaletteSize</span>(self: *<span class="tok-kw">const</span> Self) <span class="tok-type">u16</span> {</span>
<span class="line" id="L138"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (self.bit_depth &gt; <span class="tok-number">8</span>) <span class="tok-number">256</span> <span class="tok-kw">else</span> <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">1</span>) &lt;&lt; <span class="tok-builtin">@truncate</span>(self.bit_depth);</span>
<span class="line" id="L139"> }</span>
<span class="line" id="L140"></span>
<span class="line" id="L141"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">channelCount</span>(self: *<span class="tok-kw">const</span> Self) <span class="tok-type">u8</span> {</span>
<span class="line" id="L142"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.color_type) {</span>
<span class="line" id="L143"> .grayscale =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L144"> .rgb_color =&gt; <span class="tok-number">3</span>,</span>
<span class="line" id="L145"> .indexed =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L146"> .grayscale_alpha =&gt; <span class="tok-number">2</span>,</span>
<span class="line" id="L147"> .rgba_color =&gt; <span class="tok-number">4</span>,</span>
<span class="line" id="L148"> };</span>
<span class="line" id="L149"> }</span>
<span class="line" id="L150"></span>
<span class="line" id="L151"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pixelBits</span>(self: *<span class="tok-kw">const</span> Self) <span class="tok-type">u8</span> {</span>
<span class="line" id="L152"> <span class="tok-kw">return</span> self.bit_depth * self.channelCount();</span>
<span class="line" id="L153"> }</span>
<span class="line" id="L154"></span>
<span class="line" id="L155"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">lineBytes</span>(self: *<span class="tok-kw">const</span> Self) <span class="tok-type">u32</span> {</span>
<span class="line" id="L156"> <span class="tok-kw">return</span> (self.pixelBits() * self.width + <span class="tok-number">7</span>) / <span class="tok-number">8</span>;</span>
<span class="line" id="L157"> }</span>
<span class="line" id="L158"></span>
<span class="line" id="L159"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPixelFormat</span>(self: *<span class="tok-kw">const</span> Self) PixelFormat {</span>
<span class="line" id="L160"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.color_type) {</span>
<span class="line" id="L161"> .grayscale =&gt; <span class="tok-kw">switch</span> (self.bit_depth) {</span>
<span class="line" id="L162"> <span class="tok-number">1</span> =&gt; PixelFormat.grayscale1,</span>
<span class="line" id="L163"> <span class="tok-number">2</span> =&gt; PixelFormat.grayscale2,</span>
<span class="line" id="L164"> <span class="tok-number">4</span> =&gt; PixelFormat.grayscale4,</span>
<span class="line" id="L165"> <span class="tok-number">8</span> =&gt; PixelFormat.grayscale8,</span>
<span class="line" id="L166"> <span class="tok-number">16</span> =&gt; PixelFormat.grayscale16,</span>
<span class="line" id="L167"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L168"> },</span>
<span class="line" id="L169"> .rgb_color =&gt; <span class="tok-kw">switch</span> (self.bit_depth) {</span>
<span class="line" id="L170"> <span class="tok-number">8</span> =&gt; PixelFormat.rgb24,</span>
<span class="line" id="L171"> <span class="tok-number">16</span> =&gt; PixelFormat.rgb48,</span>
<span class="line" id="L172"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L173"> },</span>
<span class="line" id="L174"> .indexed =&gt; <span class="tok-kw">switch</span> (self.bit_depth) {</span>
<span class="line" id="L175"> <span class="tok-number">1</span> =&gt; PixelFormat.indexed1,</span>
<span class="line" id="L176"> <span class="tok-number">2</span> =&gt; PixelFormat.indexed2,</span>
<span class="line" id="L177"> <span class="tok-number">4</span> =&gt; PixelFormat.indexed4,</span>
<span class="line" id="L178"> <span class="tok-number">8</span> =&gt; PixelFormat.indexed8,</span>
<span class="line" id="L179"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L180"> },</span>
<span class="line" id="L181"> .grayscale_alpha =&gt; <span class="tok-kw">switch</span> (self.bit_depth) {</span>
<span class="line" id="L182"> <span class="tok-number">8</span> =&gt; PixelFormat.grayscale8Alpha,</span>
<span class="line" id="L183"> <span class="tok-number">16</span> =&gt; PixelFormat.grayscale16Alpha,</span>
<span class="line" id="L184"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L185"> },</span>
<span class="line" id="L186"> .rgba_color =&gt; <span class="tok-kw">switch</span> (self.bit_depth) {</span>
<span class="line" id="L187"> <span class="tok-number">8</span> =&gt; PixelFormat.rgba32,</span>
<span class="line" id="L188"> <span class="tok-number">16</span> =&gt; PixelFormat.rgba64,</span>
<span class="line" id="L189"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L190"> },</span>
<span class="line" id="L191"> };</span>
<span class="line" id="L192"> }</span>
<span class="line" id="L193">};</span>
<span class="line" id="L194"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,186 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/png/zlib_compressor.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> io = std.io;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> deflate = std.compress.deflate;</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-comment">/// Zlib Compressor (Deflate) with a writer interface</span></span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">ZlibCompressor</span>(<span class="tok-kw">comptime</span> WriterType: <span class="tok-type">type</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L7"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L8"> raw_writer: WriterType,</span>
<span class="line" id="L9"> compressor: deflate.Compressor(WriterType),</span>
<span class="line" id="L10"> adler: std.hash.Adler32,</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"> <span class="tok-comment">// TODO: find why doing it an other way segfaults</span>
</span>
<span class="line" id="L15"> <span class="tok-comment">/// Inits a zlibcompressor</span></span>
<span class="line" id="L16"> <span class="tok-comment">/// This is made this way because not doing it in place segfaults for a reason</span></span>
<span class="line" id="L17"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(self: *Self, alloc: std.mem.Allocator, stream: WriterType) !<span class="tok-type">void</span> {</span>
<span class="line" id="L18"> self.raw_writer = stream;</span>
<span class="line" id="L19"> self.compressor = <span class="tok-kw">try</span> deflate.compressor(alloc, self.raw_writer, .{});</span>
<span class="line" id="L20"> self.adler = std.hash.Adler32.init();</span>
<span class="line" id="L21"> }</span>
<span class="line" id="L22"></span>
<span class="line" id="L23"> <span class="tok-comment">/// Begins a zlib block with the header</span></span>
<span class="line" id="L24"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">begin</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L25"> <span class="tok-comment">// TODO: customize</span>
</span>
<span class="line" id="L26"> <span class="tok-kw">const</span> compression_method = <span class="tok-number">0x78</span>; <span class="tok-comment">// 8 = deflate, 7 = log(window size (see std.compress.deflate)) - 8</span>
</span>
<span class="line" id="L27"> <span class="tok-kw">const</span> compression_flags = blk: {</span>
<span class="line" id="L28"> <span class="tok-kw">var</span> ret: <span class="tok-type">u8</span> = <span class="tok-number">0b10000000</span>; <span class="tok-comment">// 11 = max compression</span>
</span>
<span class="line" id="L29"> <span class="tok-kw">const</span> rem: <span class="tok-type">u8</span> = <span class="tok-builtin">@truncate</span>(((<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-builtin">@intCast</span>(compression_method)) &lt;&lt; <span class="tok-number">8</span>) + ret) % <span class="tok-number">31</span>);</span>
<span class="line" id="L30"> ret += <span class="tok-number">31</span> - <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@truncate</span>(rem));</span>
<span class="line" id="L31"> <span class="tok-kw">break</span> :blk ret;</span>
<span class="line" id="L32"> };</span>
<span class="line" id="L33"></span>
<span class="line" id="L34"> <span class="tok-comment">//std.debug.assert(((@intCast(usize, cmf) &lt;&lt; 8) + flg) % 31 == 0);</span>
</span>
<span class="line" id="L35"> <span class="tok-comment">// write the header</span>
</span>
<span class="line" id="L36"> <span class="tok-kw">var</span> wr = self.raw_writer;</span>
<span class="line" id="L37"> <span class="tok-kw">try</span> wr.writeByte(compression_method);</span>
<span class="line" id="L38"> <span class="tok-kw">try</span> wr.writeByte(compression_flags);</span>
<span class="line" id="L39"> }</span>
<span class="line" id="L40"></span>
<span class="line" id="L41"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Error = WriterType.Error;</span>
<span class="line" id="L42"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> Writer = std.io.Writer(*Self, Error, write);</span>
<span class="line" id="L43"></span>
<span class="line" id="L44"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writer</span>(self: *Self) Writer {</span>
<span class="line" id="L45"> <span class="tok-kw">return</span> .{ .context = self };</span>
<span class="line" id="L46"> }</span>
<span class="line" id="L47"></span>
<span class="line" id="L48"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: *Self, bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) Error!<span class="tok-type">usize</span> {</span>
<span class="line" id="L49"> <span class="tok-kw">const</span> amount = <span class="tok-kw">try</span> self.compressor.writer().write(bytes);</span>
<span class="line" id="L50"> self.adler.update(bytes[<span class="tok-number">0</span>..amount]);</span>
<span class="line" id="L51"> <span class="tok-kw">return</span> amount;</span>
<span class="line" id="L52"> }</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-comment">/// Ends a zlib block with the checksum</span></span>
<span class="line" id="L55"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">end</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L56"> <span class="tok-kw">try</span> self.compressor.close();</span>
<span class="line" id="L57"> self.compressor.deinit();</span>
<span class="line" id="L58"> <span class="tok-comment">// Write the checksum</span>
</span>
<span class="line" id="L59"> <span class="tok-kw">try</span> self.raw_writer.writeInt(<span class="tok-type">u32</span>, self.adler.final(), .big);</span>
<span class="line" id="L60"> }</span>
<span class="line" id="L61"> };</span>
<span class="line" id="L62">}</span>
<span class="line" id="L63"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,568 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/formats/qoi.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Adapted from https://github.com/MasterQ32/zig-qoi</span>
</span>
<span class="line" id="L2"><span class="tok-comment">// with permission from Felix Queißner</span>
</span>
<span class="line" id="L3"><span class="tok-kw">const</span> Allocator = std.mem.Allocator;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> buffered_stream_source = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../buffered_stream_source.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../color.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> fs = std.fs;</span>
<span class="line" id="L8"><span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../Image.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">const</span> ImageError = Image.Error;</span>
<span class="line" id="L10"><span class="tok-kw">const</span> ImageReadError = Image.ReadError;</span>
<span class="line" id="L11"><span class="tok-kw">const</span> ImageWriteError = Image.WriteError;</span>
<span class="line" id="L12"><span class="tok-kw">const</span> io = std.io;</span>
<span class="line" id="L13"><span class="tok-kw">const</span> mem = std.mem;</span>
<span class="line" id="L14"><span class="tok-kw">const</span> path = std.fs.path;</span>
<span class="line" id="L15"><span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L16"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L17"><span class="tok-kw">const</span> utils = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../utils.zig&quot;</span>);</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> QoiColor = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L20"> r: <span class="tok-type">u8</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L21"> g: <span class="tok-type">u8</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L22"> b: <span class="tok-type">u8</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L23"> a: <span class="tok-type">u8</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>) = <span class="tok-number">0xFF</span>,</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"> <span class="tok-kw">fn</span> <span class="tok-fn">hash</span>(c: QoiColor) <span class="tok-type">u6</span> {</span>
<span class="line" id="L26"> <span class="tok-kw">return</span> <span class="tok-builtin">@truncate</span>(c.r *% <span class="tok-number">3</span> +% c.g *% <span class="tok-number">5</span> +% c.b *% <span class="tok-number">7</span> +% c.a *% <span class="tok-number">11</span>);</span>
<span class="line" id="L27"> }</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eql</span>(a: QoiColor, b: QoiColor) <span class="tok-type">bool</span> {</span>
<span class="line" id="L30"> <span class="tok-kw">return</span> std.meta.eql(a, b);</span>
<span class="line" id="L31"> }</span>
<span class="line" id="L32"></span>
<span class="line" id="L33"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toRgb24</span>(self: QoiColor) color.Rgb24 {</span>
<span class="line" id="L34"> <span class="tok-kw">return</span> color.Rgb24{</span>
<span class="line" id="L35"> .r = self.r,</span>
<span class="line" id="L36"> .g = self.g,</span>
<span class="line" id="L37"> .b = self.b,</span>
<span class="line" id="L38"> };</span>
<span class="line" id="L39"> }</span>
<span class="line" id="L40"></span>
<span class="line" id="L41"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toRgba32</span>(self: QoiColor) color.Rgba32 {</span>
<span class="line" id="L42"> <span class="tok-kw">return</span> color.Rgba32{</span>
<span class="line" id="L43"> .r = self.r,</span>
<span class="line" id="L44"> .g = self.g,</span>
<span class="line" id="L45"> .b = self.b,</span>
<span class="line" id="L46"> .a = self.a,</span>
<span class="line" id="L47"> };</span>
<span class="line" id="L48"> }</span>
<span class="line" id="L49"></span>
<span class="line" id="L50"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">from</span>(pixel: <span class="tok-kw">anytype</span>) QoiColor {</span>
<span class="line" id="L51"> <span class="tok-kw">if</span> (<span class="tok-builtin">@TypeOf</span>(pixel) == color.Rgb24) {</span>
<span class="line" id="L52"> <span class="tok-kw">return</span> QoiColor{</span>
<span class="line" id="L53"> .r = pixel.r,</span>
<span class="line" id="L54"> .g = pixel.g,</span>
<span class="line" id="L55"> .b = pixel.b,</span>
<span class="line" id="L56"> };</span>
<span class="line" id="L57"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (<span class="tok-builtin">@TypeOf</span>(pixel) == color.Rgba32) {</span>
<span class="line" id="L58"> <span class="tok-kw">return</span> QoiColor{</span>
<span class="line" id="L59"> .r = pixel.r,</span>
<span class="line" id="L60"> .g = pixel.g,</span>
<span class="line" id="L61"> .b = pixel.b,</span>
<span class="line" id="L62"> .a = pixel.a,</span>
<span class="line" id="L63"> };</span>
<span class="line" id="L64"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L65"> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L66"> }</span>
<span class="line" id="L67"> }</span>
<span class="line" id="L68">};</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Colorspace = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L71"> <span class="tok-comment">/// sRGB color, linear alpha</span></span>
<span class="line" id="L72"> srgb = <span class="tok-number">0</span>,</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"> <span class="tok-comment">/// Every channel is linear</span></span>
<span class="line" id="L75"> linear = <span class="tok-number">1</span>,</span>
<span class="line" id="L76">};</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Format = <span class="tok-kw">enum</span>(<span class="tok-type">u8</span>) {</span>
<span class="line" id="L79"> rgb = <span class="tok-number">3</span>,</span>
<span class="line" id="L80"> rgba = <span class="tok-number">4</span>,</span>
<span class="line" id="L81">};</span>
<span class="line" id="L82"></span>
<span class="line" id="L83"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Header = <span class="tok-kw">extern</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L84"> <span class="tok-kw">const</span> size = <span class="tok-number">14</span>;</span>
<span class="line" id="L85"> <span class="tok-kw">const</span> correct_magic = [<span class="tok-number">4</span>]<span class="tok-type">u8</span>{ <span class="tok-str">'q'</span>, <span class="tok-str">'o'</span>, <span class="tok-str">'i'</span>, <span class="tok-str">'f'</span> };</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> width: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L88"> height: <span class="tok-type">u32</span> <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L89"> format: Format <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L90"> colorspace: Colorspace <span class="tok-kw">align</span>(<span class="tok-number">1</span>),</span>
<span class="line" id="L91"></span>
<span class="line" id="L92"> <span class="tok-kw">fn</span> <span class="tok-fn">encode</span>(header: Header) [size]<span class="tok-type">u8</span> {</span>
<span class="line" id="L93"> <span class="tok-kw">var</span> result: [size]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L94"> <span class="tok-builtin">@memcpy</span>(result[<span class="tok-number">0</span>..<span class="tok-number">4</span>], &amp;correct_magic);</span>
<span class="line" id="L95"> std.mem.writeInt(<span class="tok-type">u32</span>, result[<span class="tok-number">4</span>..<span class="tok-number">8</span>], header.width, .big);</span>
<span class="line" id="L96"> std.mem.writeInt(<span class="tok-type">u32</span>, result[<span class="tok-number">8</span>..<span class="tok-number">12</span>], header.height, .big);</span>
<span class="line" id="L97"> result[<span class="tok-number">12</span>] = <span class="tok-builtin">@intFromEnum</span>(header.format);</span>
<span class="line" id="L98"> result[<span class="tok-number">13</span>] = <span class="tok-builtin">@intFromEnum</span>(header.colorspace);</span>
<span class="line" id="L99"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L100"> }</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"> <span class="tok-kw">comptime</span> {</span>
<span class="line" id="L103"> std.debug.assert((<span class="tok-builtin">@sizeOf</span>(Header) + Header.correct_magic.len) == Header.size);</span>
<span class="line" id="L104"> }</span>
<span class="line" id="L105">};</span>
<span class="line" id="L106"></span>
<span class="line" id="L107"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> QOI = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L108"> header: Header = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L109"></span>
<span class="line" id="L110"> <span class="tok-kw">pub</span> <span class="tok-kw">const</span> EncoderOptions = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L111"> colorspace: Colorspace = .srgb,</span>
<span class="line" id="L112"> };</span>
<span class="line" id="L113"></span>
<span class="line" id="L114"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L115"></span>
<span class="line" id="L116"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatInterface</span>() FormatInterface {</span>
<span class="line" id="L117"> <span class="tok-kw">return</span> FormatInterface{</span>
<span class="line" id="L118"> .format = format,</span>
<span class="line" id="L119"> .formatDetect = formatDetect,</span>
<span class="line" id="L120"> .readImage = readImage,</span>
<span class="line" id="L121"> .writeImage = writeImage,</span>
<span class="line" id="L122"> };</span>
<span class="line" id="L123"> }</span>
<span class="line" id="L124"></span>
<span class="line" id="L125"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">format</span>() Image.Format {</span>
<span class="line" id="L126"> <span class="tok-kw">return</span> Image.Format.qoi;</span>
<span class="line" id="L127"> }</span>
<span class="line" id="L128"></span>
<span class="line" id="L129"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">formatDetect</span>(stream: *Image.Stream) ImageReadError!<span class="tok-type">bool</span> {</span>
<span class="line" id="L130"> <span class="tok-kw">var</span> magic_buffer: [Header.correct_magic.len]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L131"></span>
<span class="line" id="L132"> _ = <span class="tok-kw">try</span> stream.read(magic_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L133"></span>
<span class="line" id="L134"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, magic_buffer[<span class="tok-number">0</span>..], Header.correct_magic[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L135"> }</span>
<span class="line" id="L136"></span>
<span class="line" id="L137"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readImage</span>(allocator: Allocator, stream: *Image.Stream) ImageReadError!Image {</span>
<span class="line" id="L138"> <span class="tok-kw">var</span> result = Image.init(allocator);</span>
<span class="line" id="L139"> <span class="tok-kw">errdefer</span> result.deinit();</span>
<span class="line" id="L140"> <span class="tok-kw">var</span> qoi = Self{};</span>
<span class="line" id="L141"></span>
<span class="line" id="L142"> <span class="tok-kw">const</span> pixels = <span class="tok-kw">try</span> qoi.read(allocator, stream);</span>
<span class="line" id="L143"></span>
<span class="line" id="L144"> result.width = qoi.width();</span>
<span class="line" id="L145"> result.height = qoi.height();</span>
<span class="line" id="L146"> result.pixels = pixels;</span>
<span class="line" id="L147"></span>
<span class="line" id="L148"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L149"> }</span>
<span class="line" id="L150"></span>
<span class="line" id="L151"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeImage</span>(allocator: Allocator, write_stream: *Image.Stream, image: Image, encoder_options: Image.EncoderOptions) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L152"> _ = allocator;</span>
<span class="line" id="L153"></span>
<span class="line" id="L154"> <span class="tok-kw">var</span> qoi = Self{};</span>
<span class="line" id="L155"> qoi.header.width = <span class="tok-builtin">@truncate</span>(image.width);</span>
<span class="line" id="L156"> qoi.header.height = <span class="tok-builtin">@truncate</span>(image.height);</span>
<span class="line" id="L157"> qoi.header.format = <span class="tok-kw">switch</span> (image.pixels) {</span>
<span class="line" id="L158"> .rgb24 =&gt; Format.rgb,</span>
<span class="line" id="L159"> .rgba32 =&gt; Format.rgba,</span>
<span class="line" id="L160"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> ImageError.Unsupported,</span>
<span class="line" id="L161"> };</span>
<span class="line" id="L162"> <span class="tok-kw">switch</span> (encoder_options) {</span>
<span class="line" id="L163"> .qoi =&gt; |qoi_encode_options| {</span>
<span class="line" id="L164"> qoi.header.colorspace = qoi_encode_options.colorspace;</span>
<span class="line" id="L165"> },</span>
<span class="line" id="L166"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L167"> qoi.header.colorspace = .srgb;</span>
<span class="line" id="L168"> },</span>
<span class="line" id="L169"> }</span>
<span class="line" id="L170"></span>
<span class="line" id="L171"> <span class="tok-kw">try</span> qoi.write(write_stream, image.pixels);</span>
<span class="line" id="L172"> }</span>
<span class="line" id="L173"></span>
<span class="line" id="L174"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">width</span>(self: Self) <span class="tok-type">usize</span> {</span>
<span class="line" id="L175"> <span class="tok-kw">return</span> self.header.width;</span>
<span class="line" id="L176"> }</span>
<span class="line" id="L177"></span>
<span class="line" id="L178"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">height</span>(self: Self) <span class="tok-type">usize</span> {</span>
<span class="line" id="L179"> <span class="tok-kw">return</span> self.header.height;</span>
<span class="line" id="L180"> }</span>
<span class="line" id="L181"></span>
<span class="line" id="L182"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pixelFormat</span>(self: Self) !PixelFormat {</span>
<span class="line" id="L183"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self.header.format) {</span>
<span class="line" id="L184"> .rgb =&gt; PixelFormat.rgb24,</span>
<span class="line" id="L185"> .rgba =&gt; PixelFormat.rgba32,</span>
<span class="line" id="L186"> };</span>
<span class="line" id="L187"> }</span>
<span class="line" id="L188"></span>
<span class="line" id="L189"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">read</span>(self: *Self, allocator: Allocator, stream: *Image.Stream) ImageReadError!color.PixelStorage {</span>
<span class="line" id="L190"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceReader(stream);</span>
<span class="line" id="L191"></span>
<span class="line" id="L192"> <span class="tok-kw">var</span> magic_buffer: [Header.correct_magic.len]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L193"></span>
<span class="line" id="L194"> <span class="tok-kw">const</span> reader = buffered_stream.reader();</span>
<span class="line" id="L195"></span>
<span class="line" id="L196"> _ = <span class="tok-kw">try</span> buffered_stream.read(magic_buffer[<span class="tok-number">0</span>..]);</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-kw">if</span> (!std.mem.eql(<span class="tok-type">u8</span>, magic_buffer[<span class="tok-number">0</span>..], Header.correct_magic[<span class="tok-number">0</span>..])) {</span>
<span class="line" id="L199"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L200"> }</span>
<span class="line" id="L201"></span>
<span class="line" id="L202"> self.header = utils.readStruct(reader, Header, .big) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L203"></span>
<span class="line" id="L204"> <span class="tok-kw">const</span> pixel_format = <span class="tok-kw">try</span> self.pixelFormat();</span>
<span class="line" id="L205"></span>
<span class="line" id="L206"> <span class="tok-kw">var</span> pixels = <span class="tok-kw">try</span> color.PixelStorage.init(allocator, pixel_format, self.width() * self.height());</span>
<span class="line" id="L207"> <span class="tok-kw">errdefer</span> pixels.deinit(allocator);</span>
<span class="line" id="L208"></span>
<span class="line" id="L209"> <span class="tok-kw">var</span> current_color = QoiColor{ .r = <span class="tok-number">0</span>, .g = <span class="tok-number">0</span>, .b = <span class="tok-number">0</span>, .a = <span class="tok-number">0xFF</span> };</span>
<span class="line" id="L210"> <span class="tok-kw">var</span> color_lut = std.mem.zeroes([<span class="tok-number">64</span>]QoiColor);</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"> <span class="tok-kw">var</span> index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L213"> <span class="tok-kw">const</span> pixels_size: <span class="tok-type">usize</span> = <span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, self.header.width) * <span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, self.header.height);</span>
<span class="line" id="L214"></span>
<span class="line" id="L215"> <span class="tok-kw">while</span> (index &lt; pixels_size) {</span>
<span class="line" id="L216"> <span class="tok-kw">const</span> byte = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L217"></span>
<span class="line" id="L218"> <span class="tok-kw">var</span> new_color = current_color;</span>
<span class="line" id="L219"> <span class="tok-kw">var</span> count: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L220"></span>
<span class="line" id="L221"> <span class="tok-kw">if</span> (byte == <span class="tok-number">0b11111110</span>) { <span class="tok-comment">// QOI_OP_RGB</span>
</span>
<span class="line" id="L222"> new_color.r = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L223"> new_color.g = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L224"> new_color.b = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L225"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (byte == <span class="tok-number">0b11111111</span>) { <span class="tok-comment">// QOI_OP_RGBA</span>
</span>
<span class="line" id="L226"> new_color.r = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L227"> new_color.g = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L228"> new_color.b = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L229"> new_color.a = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L230"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (hasPrefix(byte, <span class="tok-type">u2</span>, <span class="tok-number">0b00</span>)) { <span class="tok-comment">// QOI_OP_INDEX</span>
</span>
<span class="line" id="L231"> <span class="tok-kw">const</span> color_index: <span class="tok-type">u6</span> = <span class="tok-builtin">@truncate</span>(byte);</span>
<span class="line" id="L232"> new_color = color_lut[color_index];</span>
<span class="line" id="L233"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (hasPrefix(byte, <span class="tok-type">u2</span>, <span class="tok-number">0b01</span>)) { <span class="tok-comment">// QOI_OP_DIFF</span>
</span>
<span class="line" id="L234"> <span class="tok-kw">const</span> diff_r = unmapRange2(byte &gt;&gt; <span class="tok-number">4</span>);</span>
<span class="line" id="L235"> <span class="tok-kw">const</span> diff_g = unmapRange2(byte &gt;&gt; <span class="tok-number">2</span>);</span>
<span class="line" id="L236"> <span class="tok-kw">const</span> diff_b = unmapRange2(byte &gt;&gt; <span class="tok-number">0</span>);</span>
<span class="line" id="L237"></span>
<span class="line" id="L238"> add8(&amp;new_color.r, diff_r);</span>
<span class="line" id="L239"> add8(&amp;new_color.g, diff_g);</span>
<span class="line" id="L240"> add8(&amp;new_color.b, diff_b);</span>
<span class="line" id="L241"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (hasPrefix(byte, <span class="tok-type">u2</span>, <span class="tok-number">0b10</span>)) { <span class="tok-comment">// QOI_OP_LUMA</span>
</span>
<span class="line" id="L242"> <span class="tok-kw">const</span> diff_g = unmapRange6(byte);</span>
<span class="line" id="L243"></span>
<span class="line" id="L244"> <span class="tok-kw">const</span> diff_rg_rb = <span class="tok-kw">try</span> reader.readByte();</span>
<span class="line" id="L245"></span>
<span class="line" id="L246"> <span class="tok-kw">const</span> diff_rg = unmapRange4(diff_rg_rb &gt;&gt; <span class="tok-number">4</span>);</span>
<span class="line" id="L247"> <span class="tok-kw">const</span> diff_rb = unmapRange4(diff_rg_rb &gt;&gt; <span class="tok-number">0</span>);</span>
<span class="line" id="L248"></span>
<span class="line" id="L249"> <span class="tok-kw">const</span> diff_r = <span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, diff_g) + diff_rg;</span>
<span class="line" id="L250"> <span class="tok-kw">const</span> diff_b = <span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, diff_g) + diff_rb;</span>
<span class="line" id="L251"></span>
<span class="line" id="L252"> add8(&amp;new_color.r, diff_r);</span>
<span class="line" id="L253"> add8(&amp;new_color.g, diff_g);</span>
<span class="line" id="L254"> add8(&amp;new_color.b, diff_b);</span>
<span class="line" id="L255"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (hasPrefix(byte, <span class="tok-type">u2</span>, <span class="tok-number">0b11</span>)) { <span class="tok-comment">// QOI_OP_RUN</span>
</span>
<span class="line" id="L256"> count = <span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-builtin">@as</span>(<span class="tok-type">u6</span>, <span class="tok-builtin">@truncate</span>(byte))) + <span class="tok-number">1</span>;</span>
<span class="line" id="L257"> std.debug.assert(count &gt;= <span class="tok-number">1</span> <span class="tok-kw">and</span> count &lt;= <span class="tok-number">62</span>);</span>
<span class="line" id="L258"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L259"> <span class="tok-comment">// we have covered all possibilities.</span>
</span>
<span class="line" id="L260"> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L261"> }</span>
<span class="line" id="L262"></span>
<span class="line" id="L263"> <span class="tok-comment">// this will happen when a file has an invalid run length</span>
</span>
<span class="line" id="L264"> <span class="tok-comment">// and we would decode more pixels than there are in the image.</span>
</span>
<span class="line" id="L265"> <span class="tok-kw">if</span> (index + count &gt; pixels_size) {</span>
<span class="line" id="L266"> <span class="tok-kw">return</span> ImageReadError.InvalidData;</span>
<span class="line" id="L267"> }</span>
<span class="line" id="L268"></span>
<span class="line" id="L269"> <span class="tok-kw">while</span> (count &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L270"> count -= <span class="tok-number">1</span>;</span>
<span class="line" id="L271"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L272"> .rgb24 =&gt; |data| {</span>
<span class="line" id="L273"> data[index] = new_color.toRgb24();</span>
<span class="line" id="L274"> },</span>
<span class="line" id="L275"> .rgba32 =&gt; |data| {</span>
<span class="line" id="L276"> data[index] = new_color.toRgba32();</span>
<span class="line" id="L277"> },</span>
<span class="line" id="L278"> <span class="tok-kw">else</span> =&gt; {},</span>
<span class="line" id="L279"> }</span>
<span class="line" id="L280"> index += <span class="tok-number">1</span>;</span>
<span class="line" id="L281"> }</span>
<span class="line" id="L282"></span>
<span class="line" id="L283"> color_lut[new_color.hash()] = new_color;</span>
<span class="line" id="L284"> current_color = new_color;</span>
<span class="line" id="L285"> }</span>
<span class="line" id="L286"></span>
<span class="line" id="L287"> <span class="tok-kw">return</span> pixels;</span>
<span class="line" id="L288"> }</span>
<span class="line" id="L289"></span>
<span class="line" id="L290"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">write</span>(self: Self, stream: *Image.Stream, pixels: color.PixelStorage) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L291"> <span class="tok-kw">var</span> buffered_stream = buffered_stream_source.bufferedStreamSourceWriter(stream);</span>
<span class="line" id="L292"> <span class="tok-kw">const</span> writer = buffered_stream.writer();</span>
<span class="line" id="L293"> <span class="tok-kw">try</span> writer.writeAll(&amp;self.header.encode());</span>
<span class="line" id="L294"></span>
<span class="line" id="L295"> <span class="tok-kw">switch</span> (pixels) {</span>
<span class="line" id="L296"> .rgb24 =&gt; |data| {</span>
<span class="line" id="L297"> <span class="tok-kw">try</span> writeData(writer, data);</span>
<span class="line" id="L298"> },</span>
<span class="line" id="L299"> .rgba32 =&gt; |data| {</span>
<span class="line" id="L300"> <span class="tok-kw">try</span> writeData(writer, data);</span>
<span class="line" id="L301"> },</span>
<span class="line" id="L302"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L303"> <span class="tok-kw">return</span> ImageError.Unsupported;</span>
<span class="line" id="L304"> },</span>
<span class="line" id="L305"> }</span>
<span class="line" id="L306"></span>
<span class="line" id="L307"> <span class="tok-kw">try</span> writer.writeAll(&amp;[<span class="tok-number">8</span>]<span class="tok-type">u8</span>{</span>
<span class="line" id="L308"> <span class="tok-number">0x00</span>,</span>
<span class="line" id="L309"> <span class="tok-number">0x00</span>,</span>
<span class="line" id="L310"> <span class="tok-number">0x00</span>,</span>
<span class="line" id="L311"> <span class="tok-number">0x00</span>,</span>
<span class="line" id="L312"> <span class="tok-number">0x00</span>,</span>
<span class="line" id="L313"> <span class="tok-number">0x00</span>,</span>
<span class="line" id="L314"> <span class="tok-number">0x00</span>,</span>
<span class="line" id="L315"> <span class="tok-number">0x01</span>,</span>
<span class="line" id="L316"> });</span>
<span class="line" id="L317"></span>
<span class="line" id="L318"> <span class="tok-kw">try</span> buffered_stream.flush();</span>
<span class="line" id="L319"> }</span>
<span class="line" id="L320"></span>
<span class="line" id="L321"> <span class="tok-kw">fn</span> <span class="tok-fn">writeData</span>(writer: buffered_stream_source.DefaultBufferedStreamSourceWriter.Writer, pixels_data: <span class="tok-kw">anytype</span>) ImageWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L322"> <span class="tok-kw">var</span> color_lut = std.mem.zeroes([<span class="tok-number">64</span>]QoiColor);</span>
<span class="line" id="L323"></span>
<span class="line" id="L324"> <span class="tok-kw">var</span> previous_pixel = QoiColor{ .r = <span class="tok-number">0</span>, .g = <span class="tok-number">0</span>, .b = <span class="tok-number">0</span>, .a = <span class="tok-number">0xFF</span> };</span>
<span class="line" id="L325"> <span class="tok-kw">var</span> run_length: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L326"></span>
<span class="line" id="L327"> <span class="tok-kw">for</span> (pixels_data, <span class="tok-number">0</span>..) |current_color, i| {</span>
<span class="line" id="L328"> <span class="tok-kw">const</span> pixel = QoiColor.from(current_color);</span>
<span class="line" id="L329"></span>
<span class="line" id="L330"> <span class="tok-kw">defer</span> previous_pixel = pixel;</span>
<span class="line" id="L331"></span>
<span class="line" id="L332"> <span class="tok-kw">const</span> same_pixel = pixel.eql(previous_pixel);</span>
<span class="line" id="L333"></span>
<span class="line" id="L334"> <span class="tok-kw">if</span> (same_pixel) {</span>
<span class="line" id="L335"> run_length += <span class="tok-number">1</span>;</span>
<span class="line" id="L336"> }</span>
<span class="line" id="L337"></span>
<span class="line" id="L338"> <span class="tok-kw">if</span> (run_length &gt; <span class="tok-number">0</span> <span class="tok-kw">and</span> (run_length == <span class="tok-number">62</span> <span class="tok-kw">or</span> !same_pixel <span class="tok-kw">or</span> (i == (pixels_data.len - <span class="tok-number">1</span>)))) {</span>
<span class="line" id="L339"> <span class="tok-comment">// QOI_OP_RUN</span>
</span>
<span class="line" id="L340"> std.debug.assert(run_length &gt;= <span class="tok-number">1</span> <span class="tok-kw">and</span> run_length &lt;= <span class="tok-number">62</span>);</span>
<span class="line" id="L341"> <span class="tok-kw">try</span> writer.writeByte(<span class="tok-number">0b1100_0000</span> | <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-builtin">@truncate</span>(run_length - <span class="tok-number">1</span>)));</span>
<span class="line" id="L342"> run_length = <span class="tok-number">0</span>;</span>
<span class="line" id="L343"> }</span>
<span class="line" id="L344"></span>
<span class="line" id="L345"> <span class="tok-kw">if</span> (!same_pixel) {</span>
<span class="line" id="L346"> <span class="tok-kw">const</span> hash = pixel.hash();</span>
<span class="line" id="L347"> <span class="tok-kw">if</span> (color_lut[hash].eql(pixel)) {</span>
<span class="line" id="L348"> <span class="tok-comment">// QOI_OP_INDEX</span>
</span>
<span class="line" id="L349"> <span class="tok-kw">try</span> writer.writeByte(<span class="tok-number">0b0000_0000</span> | hash);</span>
<span class="line" id="L350"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L351"> color_lut[hash] = pixel;</span>
<span class="line" id="L352"></span>
<span class="line" id="L353"> <span class="tok-kw">const</span> diff_r = <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, pixel.r) - <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, previous_pixel.r);</span>
<span class="line" id="L354"> <span class="tok-kw">const</span> diff_g = <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, pixel.g) - <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, previous_pixel.g);</span>
<span class="line" id="L355"> <span class="tok-kw">const</span> diff_b = <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, pixel.b) - <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, previous_pixel.b);</span>
<span class="line" id="L356"> <span class="tok-kw">const</span> diff_a = <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, pixel.a) - <span class="tok-builtin">@as</span>(<span class="tok-type">i16</span>, previous_pixel.a);</span>
<span class="line" id="L357"></span>
<span class="line" id="L358"> <span class="tok-kw">const</span> diff_rg = diff_r - diff_g;</span>
<span class="line" id="L359"> <span class="tok-kw">const</span> diff_rb = diff_b - diff_g;</span>
<span class="line" id="L360"></span>
<span class="line" id="L361"> <span class="tok-kw">if</span> (diff_a == <span class="tok-number">0</span> <span class="tok-kw">and</span> inRange2(diff_r) <span class="tok-kw">and</span> inRange2(diff_g) <span class="tok-kw">and</span> inRange2(diff_b)) {</span>
<span class="line" id="L362"> <span class="tok-comment">// QOI_OP_DIFF</span>
</span>
<span class="line" id="L363"> <span class="tok-kw">const</span> byte = <span class="tok-number">0b0100_0000</span> |</span>
<span class="line" id="L364"> (mapRange2(diff_r) &lt;&lt; <span class="tok-number">4</span>) |</span>
<span class="line" id="L365"> (mapRange2(diff_g) &lt;&lt; <span class="tok-number">2</span>) |</span>
<span class="line" id="L366"> (mapRange2(diff_b) &lt;&lt; <span class="tok-number">0</span>);</span>
<span class="line" id="L367"> <span class="tok-kw">try</span> writer.writeByte(byte);</span>
<span class="line" id="L368"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (diff_a == <span class="tok-number">0</span> <span class="tok-kw">and</span> inRange6(diff_g) <span class="tok-kw">and</span> inRange4(diff_rg) <span class="tok-kw">and</span> inRange4(diff_rb)) {</span>
<span class="line" id="L369"> <span class="tok-comment">// QOI_OP_LUMA</span>
</span>
<span class="line" id="L370"> <span class="tok-kw">try</span> writer.writeAll(&amp;[<span class="tok-number">2</span>]<span class="tok-type">u8</span>{</span>
<span class="line" id="L371"> <span class="tok-number">0b1000_0000</span> | mapRange6(diff_g),</span>
<span class="line" id="L372"> (mapRange4(diff_rg) &lt;&lt; <span class="tok-number">4</span>) | (mapRange4(diff_rb) &lt;&lt; <span class="tok-number">0</span>),</span>
<span class="line" id="L373"> });</span>
<span class="line" id="L374"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (diff_a == <span class="tok-number">0</span>) {</span>
<span class="line" id="L375"> <span class="tok-comment">// QOI_OP_RGB</span>
</span>
<span class="line" id="L376"> <span class="tok-kw">try</span> writer.writeAll(&amp;[<span class="tok-number">4</span>]<span class="tok-type">u8</span>{</span>
<span class="line" id="L377"> <span class="tok-number">0b1111_1110</span>,</span>
<span class="line" id="L378"> pixel.r,</span>
<span class="line" id="L379"> pixel.g,</span>
<span class="line" id="L380"> pixel.b,</span>
<span class="line" id="L381"> });</span>
<span class="line" id="L382"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L383"> <span class="tok-comment">// QOI_OP_RGBA</span>
</span>
<span class="line" id="L384"> <span class="tok-kw">try</span> writer.writeAll(&amp;[<span class="tok-number">5</span>]<span class="tok-type">u8</span>{</span>
<span class="line" id="L385"> <span class="tok-number">0b1111_1111</span>,</span>
<span class="line" id="L386"> pixel.r,</span>
<span class="line" id="L387"> pixel.g,</span>
<span class="line" id="L388"> pixel.b,</span>
<span class="line" id="L389"> pixel.a,</span>
<span class="line" id="L390"> });</span>
<span class="line" id="L391"> }</span>
<span class="line" id="L392"> }</span>
<span class="line" id="L393"> }</span>
<span class="line" id="L394"> }</span>
<span class="line" id="L395"> }</span>
<span class="line" id="L396"></span>
<span class="line" id="L397"> <span class="tok-kw">fn</span> <span class="tok-fn">mapRange2</span>(val: <span class="tok-type">i16</span>) <span class="tok-type">u8</span> {</span>
<span class="line" id="L398"> <span class="tok-kw">return</span> <span class="tok-builtin">@as</span>(<span class="tok-type">u2</span>, <span class="tok-builtin">@intCast</span>(val + <span class="tok-number">2</span>));</span>
<span class="line" id="L399"> }</span>
<span class="line" id="L400"> <span class="tok-kw">fn</span> <span class="tok-fn">mapRange4</span>(val: <span class="tok-type">i16</span>) <span class="tok-type">u8</span> {</span>
<span class="line" id="L401"> <span class="tok-kw">return</span> <span class="tok-builtin">@as</span>(<span class="tok-type">u4</span>, <span class="tok-builtin">@intCast</span>(val + <span class="tok-number">8</span>));</span>
<span class="line" id="L402"> }</span>
<span class="line" id="L403"> <span class="tok-kw">fn</span> <span class="tok-fn">mapRange6</span>(val: <span class="tok-type">i16</span>) <span class="tok-type">u8</span> {</span>
<span class="line" id="L404"> <span class="tok-kw">return</span> <span class="tok-builtin">@as</span>(<span class="tok-type">u6</span>, <span class="tok-builtin">@intCast</span>(val + <span class="tok-number">32</span>));</span>
<span class="line" id="L405"> }</span>
<span class="line" id="L406"></span>
<span class="line" id="L407"> <span class="tok-kw">fn</span> <span class="tok-fn">unmapRange2</span>(val: <span class="tok-type">u32</span>) <span class="tok-type">i2</span> {</span>
<span class="line" id="L408"> <span class="tok-kw">return</span> <span class="tok-builtin">@as</span>(<span class="tok-type">i2</span>, <span class="tok-builtin">@intCast</span>(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-builtin">@as</span>(<span class="tok-type">u2</span>, <span class="tok-builtin">@truncate</span>(val))) - <span class="tok-number">2</span>));</span>
<span class="line" id="L409"> }</span>
<span class="line" id="L410"> <span class="tok-kw">fn</span> <span class="tok-fn">unmapRange4</span>(val: <span class="tok-type">u32</span>) <span class="tok-type">i4</span> {</span>
<span class="line" id="L411"> <span class="tok-kw">return</span> <span class="tok-builtin">@as</span>(<span class="tok-type">i4</span>, <span class="tok-builtin">@intCast</span>(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-builtin">@as</span>(<span class="tok-type">u4</span>, <span class="tok-builtin">@truncate</span>(val))) - <span class="tok-number">8</span>));</span>
<span class="line" id="L412"> }</span>
<span class="line" id="L413"> <span class="tok-kw">fn</span> <span class="tok-fn">unmapRange6</span>(val: <span class="tok-type">u32</span>) <span class="tok-type">i6</span> {</span>
<span class="line" id="L414"> <span class="tok-kw">return</span> <span class="tok-builtin">@as</span>(<span class="tok-type">i6</span>, <span class="tok-builtin">@intCast</span>(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-builtin">@as</span>(<span class="tok-type">u6</span>, <span class="tok-builtin">@truncate</span>(val))) - <span class="tok-number">32</span>));</span>
<span class="line" id="L415"> }</span>
<span class="line" id="L416"></span>
<span class="line" id="L417"> <span class="tok-kw">fn</span> <span class="tok-fn">inRange2</span>(val: <span class="tok-type">i16</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L418"> <span class="tok-kw">return</span> (val &gt;= -<span class="tok-number">2</span>) <span class="tok-kw">and</span> (val &lt;= <span class="tok-number">1</span>);</span>
<span class="line" id="L419"> }</span>
<span class="line" id="L420"> <span class="tok-kw">fn</span> <span class="tok-fn">inRange4</span>(val: <span class="tok-type">i16</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L421"> <span class="tok-kw">return</span> (val &gt;= -<span class="tok-number">8</span>) <span class="tok-kw">and</span> (val &lt;= <span class="tok-number">7</span>);</span>
<span class="line" id="L422"> }</span>
<span class="line" id="L423"> <span class="tok-kw">fn</span> <span class="tok-fn">inRange6</span>(val: <span class="tok-type">i16</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L424"> <span class="tok-kw">return</span> (val &gt;= -<span class="tok-number">32</span>) <span class="tok-kw">and</span> (val &lt;= <span class="tok-number">31</span>);</span>
<span class="line" id="L425"> }</span>
<span class="line" id="L426"></span>
<span class="line" id="L427"> <span class="tok-kw">fn</span> <span class="tok-fn">add8</span>(dst: *<span class="tok-type">u8</span>, diff: <span class="tok-type">i8</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L428"> dst.* +%= <span class="tok-builtin">@bitCast</span>(diff);</span>
<span class="line" id="L429"> }</span>
<span class="line" id="L430"></span>
<span class="line" id="L431"> <span class="tok-kw">fn</span> <span class="tok-fn">hasPrefix</span>(value: <span class="tok-type">u8</span>, <span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>, prefix: T) <span class="tok-type">bool</span> {</span>
<span class="line" id="L432"> <span class="tok-kw">return</span> (<span class="tok-builtin">@as</span>(T, <span class="tok-builtin">@truncate</span>(value &gt;&gt; (<span class="tok-number">8</span> - <span class="tok-builtin">@bitSizeOf</span>(T)))) == prefix);</span>
<span class="line" id="L433"> }</span>
<span class="line" id="L434">};</span>
<span class="line" id="L435"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,335 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/octree_quantizer.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> Allocator = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>).mem.Allocator;</span>
<span class="line" id="L2"><span class="tok-kw">const</span> ArenaAllocator = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>).heap.ArenaAllocator;</span>
<span class="line" id="L3"><span class="tok-kw">const</span> ArrayList = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>).ArrayList;</span>
<span class="line" id="L4"><span class="tok-kw">const</span> Rgba32 = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;color.zig&quot;</span>).Rgba32;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> MaxDepth = <span class="tok-number">8</span>;</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> OctTreeQuantizer = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L9"> rootNode: OctTreeQuantizerNode,</span>
<span class="line" id="L10"> levels: [MaxDepth]NodeArrayList,</span>
<span class="line" id="L11"> arenaAllocator: ArenaAllocator,</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"> <span class="tok-kw">const</span> NodeArrayList = ArrayList(*OctTreeQuantizerNode);</span>
<span class="line" id="L14"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(allocator: Allocator) Self {</span>
<span class="line" id="L17"> <span class="tok-kw">var</span> result = Self{</span>
<span class="line" id="L18"> .rootNode = OctTreeQuantizerNode{},</span>
<span class="line" id="L19"> .arenaAllocator = ArenaAllocator.init(allocator),</span>
<span class="line" id="L20"> .levels = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L21"> };</span>
<span class="line" id="L22"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L23"> <span class="tok-kw">while</span> (i &lt; result.levels.len) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L24"> result.levels[i] = NodeArrayList.init(allocator);</span>
<span class="line" id="L25"> }</span>
<span class="line" id="L26"> result.rootNode.init(<span class="tok-number">0</span>, &amp;result) <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L27"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L28"> }</span>
<span class="line" id="L29"></span>
<span class="line" id="L30"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L31"> self.arenaAllocator.deinit();</span>
<span class="line" id="L32"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L33"> <span class="tok-kw">while</span> (i &lt; self.levels.len) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L34"> self.levels[i].deinit();</span>
<span class="line" id="L35"> }</span>
<span class="line" id="L36"> }</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">allocateNode</span>(self: *Self) !*OctTreeQuantizerNode {</span>
<span class="line" id="L39"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> self.arenaAllocator.allocator().create(OctTreeQuantizerNode);</span>
<span class="line" id="L40"> }</span>
<span class="line" id="L41"></span>
<span class="line" id="L42"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">addLevelNode</span>(self: *Self, level: <span class="tok-type">i32</span>, node: *OctTreeQuantizerNode) !<span class="tok-type">void</span> {</span>
<span class="line" id="L43"> <span class="tok-kw">try</span> self.levels[<span class="tok-builtin">@intCast</span>(level)].append(node);</span>
<span class="line" id="L44"> }</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">addColor</span>(self: *Self, color: Rgba32) !<span class="tok-type">void</span> {</span>
<span class="line" id="L47"> <span class="tok-kw">try</span> self.rootNode.addColor(color, <span class="tok-number">0</span>, self);</span>
<span class="line" id="L48"> }</span>
<span class="line" id="L49"></span>
<span class="line" id="L50"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPaletteIndex</span>(self: Self, color: Rgba32) !<span class="tok-type">usize</span> {</span>
<span class="line" id="L51"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> self.rootNode.getPaletteIndex(color, <span class="tok-number">0</span>);</span>
<span class="line" id="L52"> }</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">makePalette</span>(self: *Self, colorCount: <span class="tok-type">usize</span>, palette: []Rgba32) <span class="tok-type">anyerror</span>![]Rgba32 {</span>
<span class="line" id="L55"> <span class="tok-kw">var</span> paletteIndex: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L56"></span>
<span class="line" id="L57"> <span class="tok-kw">var</span> rootLeafNodes = <span class="tok-kw">try</span> self.rootNode.getLeafNodes(self.arenaAllocator.child_allocator);</span>
<span class="line" id="L58"> <span class="tok-kw">defer</span> rootLeafNodes.deinit();</span>
<span class="line" id="L59"> <span class="tok-kw">var</span> leafCount = rootLeafNodes.items.len;</span>
<span class="line" id="L60"></span>
<span class="line" id="L61"> <span class="tok-kw">var</span> level: <span class="tok-type">usize</span> = MaxDepth - <span class="tok-number">1</span>;</span>
<span class="line" id="L62"> <span class="tok-kw">while</span> (level &gt;= <span class="tok-number">0</span>) : (level -= <span class="tok-number">1</span>) {</span>
<span class="line" id="L63"> <span class="tok-kw">for</span> (self.levels[level].items) |node| {</span>
<span class="line" id="L64"> leafCount -= <span class="tok-builtin">@intCast</span>(node.removeLeaves());</span>
<span class="line" id="L65"> <span class="tok-kw">if</span> (leafCount &lt;= colorCount) {</span>
<span class="line" id="L66"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L67"> }</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"> <span class="tok-kw">if</span> (leafCount &lt;= colorCount) {</span>
<span class="line" id="L70"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L71"> }</span>
<span class="line" id="L72"> <span class="tok-kw">try</span> self.levels[level].resize(<span class="tok-number">0</span>);</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> <span class="tok-kw">var</span> processedRoofLeafNodes = <span class="tok-kw">try</span> self.rootNode.getLeafNodes(self.arenaAllocator.child_allocator);</span>
<span class="line" id="L76"> <span class="tok-kw">defer</span> processedRoofLeafNodes.deinit();</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> <span class="tok-kw">for</span> (processedRoofLeafNodes.items) |node| {</span>
<span class="line" id="L79"> <span class="tok-kw">if</span> (paletteIndex &gt;= colorCount) {</span>
<span class="line" id="L80"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L81"> }</span>
<span class="line" id="L82"> <span class="tok-kw">if</span> (node.isLeaf()) {</span>
<span class="line" id="L83"> palette[paletteIndex] = node.getColor();</span>
<span class="line" id="L84"> node.paletteIndex = paletteIndex;</span>
<span class="line" id="L85"> paletteIndex += <span class="tok-number">1</span>;</span>
<span class="line" id="L86"> }</span>
<span class="line" id="L87"> }</span>
<span class="line" id="L88"></span>
<span class="line" id="L89"> <span class="tok-kw">return</span> palette[<span class="tok-number">0</span>..paletteIndex];</span>
<span class="line" id="L90"> }</span>
<span class="line" id="L91">};</span>
<span class="line" id="L92"></span>
<span class="line" id="L93"><span class="tok-kw">const</span> OctTreeQuantizerNode = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L94"> red: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L95"> green: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L96"> blue: <span class="tok-type">u32</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L97"> referenceCount: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L98"> paletteIndex: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L99"> children: [<span class="tok-number">8</span>]?*Self = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L100"></span>
<span class="line" id="L101"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L102"> <span class="tok-kw">const</span> NodeArrayList = ArrayList(*Self);</span>
<span class="line" id="L103"></span>
<span class="line" id="L104"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(self: *Self, level: <span class="tok-type">i32</span>, parent: *OctTreeQuantizer) !<span class="tok-type">void</span> {</span>
<span class="line" id="L105"> self.red = <span class="tok-number">0</span>;</span>
<span class="line" id="L106"> self.green = <span class="tok-number">0</span>;</span>
<span class="line" id="L107"> self.blue = <span class="tok-number">0</span>;</span>
<span class="line" id="L108"> self.referenceCount = <span class="tok-number">0</span>;</span>
<span class="line" id="L109"> self.paletteIndex = <span class="tok-number">0</span>;</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L112"> <span class="tok-kw">while</span> (i &lt; self.children.len) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L113"> self.children[i] = <span class="tok-null">null</span>;</span>
<span class="line" id="L114"> }</span>
<span class="line" id="L115"></span>
<span class="line" id="L116"> <span class="tok-kw">if</span> (level &lt; (MaxDepth - <span class="tok-number">1</span>)) {</span>
<span class="line" id="L117"> <span class="tok-kw">try</span> parent.addLevelNode(level, self);</span>
<span class="line" id="L118"> }</span>
<span class="line" id="L119"> }</span>
<span class="line" id="L120"></span>
<span class="line" id="L121"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isLeaf</span>(self: Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L122"> <span class="tok-kw">return</span> self.referenceCount &gt; <span class="tok-number">0</span>;</span>
<span class="line" id="L123"> }</span>
<span class="line" id="L124"></span>
<span class="line" id="L125"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getColor</span>(self: Self) Rgba32 {</span>
<span class="line" id="L126"> <span class="tok-kw">return</span> Rgba32.initRgb(<span class="tok-builtin">@intCast</span>(self.red / self.referenceCount), <span class="tok-builtin">@intCast</span>(self.green / self.referenceCount), <span class="tok-builtin">@intCast</span>(self.blue / self.referenceCount));</span>
<span class="line" id="L127"> }</span>
<span class="line" id="L128"></span>
<span class="line" id="L129"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">addColor</span>(self: *Self, color: Rgba32, level: <span class="tok-type">i32</span>, parent: *OctTreeQuantizer) <span class="tok-type">anyerror</span>!<span class="tok-type">void</span> {</span>
<span class="line" id="L130"> <span class="tok-kw">if</span> (level &gt;= MaxDepth) {</span>
<span class="line" id="L131"> self.red += color.r;</span>
<span class="line" id="L132"> self.green += color.g;</span>
<span class="line" id="L133"> self.blue += color.b;</span>
<span class="line" id="L134"> self.referenceCount += <span class="tok-number">1</span>;</span>
<span class="line" id="L135"> <span class="tok-kw">return</span>;</span>
<span class="line" id="L136"> }</span>
<span class="line" id="L137"> <span class="tok-kw">const</span> index = getColorIndex(color, level);</span>
<span class="line" id="L138"> <span class="tok-kw">if</span> (index &gt;= self.children.len) {</span>
<span class="line" id="L139"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidColorIndex;</span>
<span class="line" id="L140"> }</span>
<span class="line" id="L141"> <span class="tok-kw">if</span> (self.children[index]) |child| {</span>
<span class="line" id="L142"> <span class="tok-kw">try</span> child.addColor(color, level + <span class="tok-number">1</span>, parent);</span>
<span class="line" id="L143"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L144"> <span class="tok-kw">var</span> newNode = <span class="tok-kw">try</span> parent.allocateNode();</span>
<span class="line" id="L145"> <span class="tok-kw">try</span> newNode.init(level, parent);</span>
<span class="line" id="L146"> <span class="tok-kw">try</span> newNode.addColor(color, level + <span class="tok-number">1</span>, parent);</span>
<span class="line" id="L147"> self.children[index] = newNode;</span>
<span class="line" id="L148"> }</span>
<span class="line" id="L149"> }</span>
<span class="line" id="L150"></span>
<span class="line" id="L151"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getPaletteIndex</span>(self: Self, color: Rgba32, level: <span class="tok-type">i32</span>) <span class="tok-type">anyerror</span>!<span class="tok-type">usize</span> {</span>
<span class="line" id="L152"> <span class="tok-kw">if</span> (self.isLeaf()) {</span>
<span class="line" id="L153"> <span class="tok-kw">return</span> self.paletteIndex;</span>
<span class="line" id="L154"> }</span>
<span class="line" id="L155"> <span class="tok-kw">const</span> index = getColorIndex(color, level);</span>
<span class="line" id="L156"> <span class="tok-kw">if</span> (self.children[index]) |child| {</span>
<span class="line" id="L157"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> child.getPaletteIndex(color, level + <span class="tok-number">1</span>);</span>
<span class="line" id="L158"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L159"> <span class="tok-kw">for</span> (self.children) |childOptional| {</span>
<span class="line" id="L160"> <span class="tok-kw">if</span> (childOptional) |child| {</span>
<span class="line" id="L161"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> child.getPaletteIndex(color, level + <span class="tok-number">1</span>);</span>
<span class="line" id="L162"> }</span>
<span class="line" id="L163"> }</span>
<span class="line" id="L164"> }</span>
<span class="line" id="L165"></span>
<span class="line" id="L166"> <span class="tok-kw">return</span> <span class="tok-kw">error</span>.ColorNotFound;</span>
<span class="line" id="L167"> }</span>
<span class="line" id="L168"></span>
<span class="line" id="L169"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">getLeafNodes</span>(self: Self, allocator: Allocator) <span class="tok-type">anyerror</span>!NodeArrayList {</span>
<span class="line" id="L170"> <span class="tok-kw">var</span> leafNodes = NodeArrayList.init(allocator);</span>
<span class="line" id="L171"></span>
<span class="line" id="L172"> <span class="tok-kw">for</span> (self.children) |childOptional| {</span>
<span class="line" id="L173"> <span class="tok-kw">if</span> (childOptional) |child| {</span>
<span class="line" id="L174"> <span class="tok-kw">if</span> (child.isLeaf()) {</span>
<span class="line" id="L175"> <span class="tok-kw">try</span> leafNodes.append(child);</span>
<span class="line" id="L176"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L177"> <span class="tok-kw">var</span> childNodes = <span class="tok-kw">try</span> child.getLeafNodes(allocator);</span>
<span class="line" id="L178"> <span class="tok-kw">defer</span> childNodes.deinit();</span>
<span class="line" id="L179"> <span class="tok-kw">for</span> (childNodes.items) |childNode| {</span>
<span class="line" id="L180"> <span class="tok-kw">try</span> leafNodes.append(childNode);</span>
<span class="line" id="L181"> }</span>
<span class="line" id="L182"> }</span>
<span class="line" id="L183"> }</span>
<span class="line" id="L184"> }</span>
<span class="line" id="L185"></span>
<span class="line" id="L186"> <span class="tok-kw">return</span> leafNodes;</span>
<span class="line" id="L187"> }</span>
<span class="line" id="L188"></span>
<span class="line" id="L189"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">removeLeaves</span>(self: *Self) <span class="tok-type">i32</span> {</span>
<span class="line" id="L190"> <span class="tok-kw">var</span> result: <span class="tok-type">i32</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L191"> <span class="tok-kw">for</span> (self.children, <span class="tok-number">0</span>..) |childOptional, i| {</span>
<span class="line" id="L192"> <span class="tok-kw">if</span> (childOptional) |child| {</span>
<span class="line" id="L193"> self.red += child.red;</span>
<span class="line" id="L194"> self.green += child.green;</span>
<span class="line" id="L195"> self.blue += child.blue;</span>
<span class="line" id="L196"> self.referenceCount += child.referenceCount;</span>
<span class="line" id="L197"> result += <span class="tok-number">1</span>;</span>
<span class="line" id="L198"> self.children[i] = <span class="tok-null">null</span>;</span>
<span class="line" id="L199"> }</span>
<span class="line" id="L200"> }</span>
<span class="line" id="L201"> <span class="tok-kw">return</span> result - <span class="tok-number">1</span>;</span>
<span class="line" id="L202"> }</span>
<span class="line" id="L203"></span>
<span class="line" id="L204"> <span class="tok-kw">inline</span> <span class="tok-kw">fn</span> <span class="tok-fn">getColorIndex</span>(color: Rgba32, level: <span class="tok-type">i32</span>) <span class="tok-type">usize</span> {</span>
<span class="line" id="L205"> <span class="tok-kw">var</span> index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L206"> <span class="tok-kw">const</span> mask = <span class="tok-builtin">@as</span>(<span class="tok-type">u8</span>, <span class="tok-number">0b10000000</span>) &gt;&gt; <span class="tok-builtin">@intCast</span>(level);</span>
<span class="line" id="L207"> <span class="tok-kw">if</span> (color.r &amp; mask != <span class="tok-number">0</span>) {</span>
<span class="line" id="L208"> index |= <span class="tok-number">0b100</span>;</span>
<span class="line" id="L209"> }</span>
<span class="line" id="L210"> <span class="tok-kw">if</span> (color.g &amp; mask != <span class="tok-number">0</span>) {</span>
<span class="line" id="L211"> index |= <span class="tok-number">0b010</span>;</span>
<span class="line" id="L212"> }</span>
<span class="line" id="L213"> <span class="tok-kw">if</span> (color.b &amp; mask != <span class="tok-number">0</span>) {</span>
<span class="line" id="L214"> index |= <span class="tok-number">0b001</span>;</span>
<span class="line" id="L215"> }</span>
<span class="line" id="L216"> <span class="tok-kw">return</span> index;</span>
<span class="line" id="L217"> }</span>
<span class="line" id="L218">};</span>
<span class="line" id="L219"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,235 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/pixel_format.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PixelFormatVariant = <span class="tok-kw">enum</span>(<span class="tok-type">u4</span>) {</span>
<span class="line" id="L2"> none = <span class="tok-number">0</span>,</span>
<span class="line" id="L3"> bgr = <span class="tok-number">1</span>,</span>
<span class="line" id="L4"> float = <span class="tok-number">2</span>,</span>
<span class="line" id="L5"> rgb565 = <span class="tok-number">3</span>,</span>
<span class="line" id="L6"> _,</span>
<span class="line" id="L7">};</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-comment">/// The values for this enum are chosen so that:</span></span>
<span class="line" id="L10"><span class="tok-comment">/// 1. value &amp; 0xFF gives number of bits per channel</span></span>
<span class="line" id="L11"><span class="tok-comment">/// 2. value &amp; 0xF00 gives number of channels</span></span>
<span class="line" id="L12"><span class="tok-comment">/// 3. value &amp; 0xF000 gives a special variant number, 1 for Bgr, 2 for Float and 3 for special Rgb 565</span></span>
<span class="line" id="L13"><span class="tok-comment">/// Note that palette index formats have number of channels set to 0.</span></span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PixelFormatInfo = <span class="tok-kw">packed</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L15"> bits_per_channel: <span class="tok-type">u8</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L16"> channel_count: <span class="tok-type">u4</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L17"> variant: PixelFormatVariant = .none,</span>
<span class="line" id="L18"> padding: <span class="tok-type">u16</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L19">};</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-kw">pub</span> <span class="tok-kw">inline</span> <span class="tok-kw">fn</span> <span class="tok-fn">toPixelFormatValue</span>(<span class="tok-kw">comptime</span> pixel_format: PixelFormatInfo) <span class="tok-type">u32</span> {</span>
<span class="line" id="L22"> <span class="tok-kw">return</span> <span class="tok-builtin">@bitCast</span>(pixel_format);</span>
<span class="line" id="L23">}</span>
<span class="line" id="L24"></span>
<span class="line" id="L25"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PixelFormat = <span class="tok-kw">enum</span>(<span class="tok-type">u32</span>) {</span>
<span class="line" id="L26"> invalid = <span class="tok-number">0</span>,</span>
<span class="line" id="L27"> indexed1 = toPixelFormatValue(.{ .bits_per_channel = <span class="tok-number">1</span> }),</span>
<span class="line" id="L28"> indexed2 = toPixelFormatValue(.{ .bits_per_channel = <span class="tok-number">2</span> }),</span>
<span class="line" id="L29"> indexed4 = toPixelFormatValue(.{ .bits_per_channel = <span class="tok-number">4</span> }),</span>
<span class="line" id="L30"> indexed8 = toPixelFormatValue(.{ .bits_per_channel = <span class="tok-number">8</span> }),</span>
<span class="line" id="L31"> indexed16 = toPixelFormatValue(.{ .bits_per_channel = <span class="tok-number">16</span> }),</span>
<span class="line" id="L32"> grayscale1 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">1</span>, .bits_per_channel = <span class="tok-number">1</span> }),</span>
<span class="line" id="L33"> grayscale2 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">1</span>, .bits_per_channel = <span class="tok-number">2</span> }),</span>
<span class="line" id="L34"> grayscale4 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">1</span>, .bits_per_channel = <span class="tok-number">4</span> }),</span>
<span class="line" id="L35"> grayscale8 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">1</span>, .bits_per_channel = <span class="tok-number">8</span> }),</span>
<span class="line" id="L36"> grayscale16 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">1</span>, .bits_per_channel = <span class="tok-number">16</span> }),</span>
<span class="line" id="L37"> grayscale8Alpha = toPixelFormatValue(.{ .channel_count = <span class="tok-number">2</span>, .bits_per_channel = <span class="tok-number">8</span> }),</span>
<span class="line" id="L38"> grayscale16Alpha = toPixelFormatValue(.{ .channel_count = <span class="tok-number">2</span>, .bits_per_channel = <span class="tok-number">16</span> }),</span>
<span class="line" id="L39"> rgb555 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">3</span>, .bits_per_channel = <span class="tok-number">5</span> }),</span>
<span class="line" id="L40"> rgb565 = toPixelFormatValue(.{ .variant = .rgb565, .channel_count = <span class="tok-number">3</span>, .bits_per_channel = <span class="tok-number">5</span> }),</span>
<span class="line" id="L41"> rgb24 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">3</span>, .bits_per_channel = <span class="tok-number">8</span> }),</span>
<span class="line" id="L42"> rgba32 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">4</span>, .bits_per_channel = <span class="tok-number">8</span> }),</span>
<span class="line" id="L43"> bgr555 = toPixelFormatValue(.{ .variant = .bgr, .channel_count = <span class="tok-number">3</span>, .bits_per_channel = <span class="tok-number">5</span> }),</span>
<span class="line" id="L44"> bgr24 = toPixelFormatValue(.{ .variant = .bgr, .channel_count = <span class="tok-number">3</span>, .bits_per_channel = <span class="tok-number">8</span> }),</span>
<span class="line" id="L45"> bgra32 = toPixelFormatValue(.{ .variant = .bgr, .channel_count = <span class="tok-number">4</span>, .bits_per_channel = <span class="tok-number">8</span> }),</span>
<span class="line" id="L46"> rgb48 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">3</span>, .bits_per_channel = <span class="tok-number">16</span> }),</span>
<span class="line" id="L47"> rgba64 = toPixelFormatValue(.{ .channel_count = <span class="tok-number">4</span>, .bits_per_channel = <span class="tok-number">16</span> }),</span>
<span class="line" id="L48"> float32 = toPixelFormatValue(.{ .variant = .float, .channel_count = <span class="tok-number">4</span>, .bits_per_channel = <span class="tok-number">32</span> }),</span>
<span class="line" id="L49"></span>
<span class="line" id="L50"> <span class="tok-kw">pub</span> <span class="tok-kw">inline</span> <span class="tok-kw">fn</span> <span class="tok-fn">info</span>(self: PixelFormat) PixelFormatInfo {</span>
<span class="line" id="L51"> <span class="tok-kw">return</span> <span class="tok-builtin">@as</span>(PixelFormatInfo, <span class="tok-builtin">@bitCast</span>(<span class="tok-builtin">@intFromEnum</span>(self)));</span>
<span class="line" id="L52"> }</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isGrayscale</span>(self: PixelFormat) <span class="tok-type">bool</span> {</span>
<span class="line" id="L55"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self) {</span>
<span class="line" id="L56"> .grayscale1, .grayscale2, .grayscale4, .grayscale8, .grayscale16, .grayscale8Alpha, .grayscale16Alpha =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L57"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">false</span>,</span>
<span class="line" id="L58"> };</span>
<span class="line" id="L59"> }</span>
<span class="line" id="L60"></span>
<span class="line" id="L61"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isIndexed</span>(self: PixelFormat) <span class="tok-type">bool</span> {</span>
<span class="line" id="L62"> <span class="tok-kw">return</span> info(self).channel_count == <span class="tok-number">0</span>;</span>
<span class="line" id="L63"> }</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isStandardRgb</span>(self: PixelFormat) <span class="tok-type">bool</span> {</span>
<span class="line" id="L66"> <span class="tok-kw">return</span> self == .rgb24 <span class="tok-kw">or</span> self == .rgb48;</span>
<span class="line" id="L67"> }</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isRgba</span>(self: PixelFormat) <span class="tok-type">bool</span> {</span>
<span class="line" id="L70"> <span class="tok-kw">return</span> self == .rgba32 <span class="tok-kw">or</span> self == .rgba64;</span>
<span class="line" id="L71"> }</span>
<span class="line" id="L72"></span>
<span class="line" id="L73"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">is16Bit</span>(self: PixelFormat) <span class="tok-type">bool</span> {</span>
<span class="line" id="L74"> <span class="tok-kw">return</span> info(self).bits_per_channel == <span class="tok-number">16</span>;</span>
<span class="line" id="L75"> }</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">pixelStride</span>(self: PixelFormat) <span class="tok-type">u8</span> {</span>
<span class="line" id="L78"> <span class="tok-kw">if</span> (self.isIndexed()) {</span>
<span class="line" id="L79"> <span class="tok-kw">return</span> (info(self).bits_per_channel + <span class="tok-number">7</span>) / <span class="tok-number">8</span>;</span>
<span class="line" id="L80"> }</span>
<span class="line" id="L81"></span>
<span class="line" id="L82"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self) {</span>
<span class="line" id="L83"> <span class="tok-kw">inline</span> <span class="tok-kw">else</span> =&gt; |value| (info(value).channel_count * info(value).bits_per_channel + <span class="tok-number">7</span>) / <span class="tok-number">8</span>,</span>
<span class="line" id="L84"> };</span>
<span class="line" id="L85"> }</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">bitsPerChannel</span>(self: PixelFormat) <span class="tok-type">u8</span> {</span>
<span class="line" id="L88"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self) {</span>
<span class="line" id="L89"> .rgb565 =&gt; <span class="tok-kw">unreachable</span>, <span class="tok-comment">// TODO: what to do in that case?</span>
</span>
<span class="line" id="L90"> <span class="tok-kw">inline</span> <span class="tok-kw">else</span> =&gt; |value| info(value).bits_per_channel,</span>
<span class="line" id="L91"> };</span>
<span class="line" id="L92"> }</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">channelCount</span>(self: PixelFormat) <span class="tok-type">u8</span> {</span>
<span class="line" id="L95"> <span class="tok-kw">if</span> (self.isIndexed()) {</span>
<span class="line" id="L96"> <span class="tok-kw">return</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L97"> }</span>
<span class="line" id="L98"></span>
<span class="line" id="L99"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (self) {</span>
<span class="line" id="L100"> <span class="tok-kw">inline</span> <span class="tok-kw">else</span> =&gt; |value| info(value).channel_count,</span>
<span class="line" id="L101"> };</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103">};</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"><span class="tok-kw">comptime</span> {</span>
<span class="line" id="L106"> <span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L107"></span>
<span class="line" id="L108"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.grayscale1) == <span class="tok-number">0x101</span>);</span>
<span class="line" id="L109"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.grayscale16) == <span class="tok-number">0x110</span>);</span>
<span class="line" id="L110"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.grayscale8Alpha) == <span class="tok-number">0x208</span>);</span>
<span class="line" id="L111"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.rgb555) == <span class="tok-number">0x305</span>);</span>
<span class="line" id="L112"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.rgb565) == <span class="tok-number">0x3305</span>);</span>
<span class="line" id="L113"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.rgba32) == <span class="tok-number">0x408</span>);</span>
<span class="line" id="L114"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.bgr24) == <span class="tok-number">0x1308</span>);</span>
<span class="line" id="L115"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.bgra32) == <span class="tok-number">0x1408</span>);</span>
<span class="line" id="L116"> std.debug.assert(<span class="tok-builtin">@intFromEnum</span>(PixelFormat.float32) == <span class="tok-number">0x2420</span>);</span>
<span class="line" id="L117">}</span>
<span class="line" id="L118"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,145 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/simd.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">load</span>(bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, <span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>, <span class="tok-kw">comptime</span> len: <span class="tok-type">u32</span>) T {</span>
<span class="line" id="L4"> <span class="tok-kw">const</span> mem = std.mem.bytesAsSlice(vectorInnerType(T), bytes);</span>
<span class="line" id="L5"> <span class="tok-kw">var</span> result: T = <span class="tok-builtin">@splat</span>(<span class="tok-builtin">@as</span>(vectorInnerType(T), <span class="tok-number">0</span>));</span>
<span class="line" id="L6"> <span class="tok-kw">const</span> vector_len = <span class="tok-kw">if</span> (len == <span class="tok-number">0</span>) vectorLength(T) <span class="tok-kw">else</span> len;</span>
<span class="line" id="L7"> <span class="tok-kw">comptime</span> <span class="tok-kw">var</span> i: <span class="tok-type">u32</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L8"> <span class="tok-kw">inline</span> <span class="tok-kw">while</span> (i &lt; vector_len) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L9"> result[i] = mem[i];</span>
<span class="line" id="L10"> }</span>
<span class="line" id="L11"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L12">}</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">fn</span> <span class="tok-fn">vectorLength</span>(<span class="tok-kw">comptime</span> VectorType: <span class="tok-type">type</span>) <span class="tok-type">comptime_int</span> {</span>
<span class="line" id="L15"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (<span class="tok-builtin">@typeInfo</span>(VectorType)) {</span>
<span class="line" id="L16"> .Vector =&gt; |info| info.len,</span>
<span class="line" id="L17"> .Array =&gt; |info| info.len,</span>
<span class="line" id="L18"> <span class="tok-kw">else</span> =&gt; <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;Invalid type &quot;</span> ++ <span class="tok-builtin">@typeName</span>(VectorType)),</span>
<span class="line" id="L19"> };</span>
<span class="line" id="L20">}</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"><span class="tok-kw">fn</span> <span class="tok-fn">vectorInnerType</span>(<span class="tok-kw">comptime</span> VectorType: <span class="tok-type">type</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L23"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (<span class="tok-builtin">@typeInfo</span>(VectorType)) {</span>
<span class="line" id="L24"> .Vector =&gt; |info| info.child,</span>
<span class="line" id="L25"> .Array =&gt; |info| info.child,</span>
<span class="line" id="L26"> <span class="tok-kw">else</span> =&gt; <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;Invalid type &quot;</span> ++ <span class="tok-builtin">@typeName</span>(VectorType)),</span>
<span class="line" id="L27"> };</span>
<span class="line" id="L28">}</span>
<span class="line" id="L29"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,295 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>src/utils.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> builtin = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;builtin&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> native_endian = builtin.target.cpu.arch.endian();</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> StructReadError = <span class="tok-kw">error</span>{ EndOfStream, InvalidData } || std.io.StreamSource.ReadError;</span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> StructWriteError = std.io.StreamSource.WriteError;</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">FixedStorage</span>(<span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>, <span class="tok-kw">comptime</span> storage_size: <span class="tok-type">usize</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L10"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L11"> data: []T = &amp;.{},</span>
<span class="line" id="L12"> storage: [storage_size]T = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">resize</span>(self: *Self, size: <span class="tok-type">usize</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L17"> self.data = self.storage[<span class="tok-number">0</span>..size];</span>
<span class="line" id="L18"> }</span>
<span class="line" id="L19"> };</span>
<span class="line" id="L20">}</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toMagicNumberNative</span>(magic: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">u32</span> {</span>
<span class="line" id="L23"> <span class="tok-kw">var</span> result: <span class="tok-type">u32</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L24"> <span class="tok-kw">for</span> (magic, <span class="tok-number">0</span>..) |character, index| {</span>
<span class="line" id="L25"> result |= (<span class="tok-builtin">@as</span>(<span class="tok-type">u32</span>, character) &lt;&lt; <span class="tok-builtin">@intCast</span>((index * <span class="tok-number">8</span>)));</span>
<span class="line" id="L26"> }</span>
<span class="line" id="L27"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L28">}</span>
<span class="line" id="L29"></span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toMagicNumberForeign</span>(magic: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">u32</span> {</span>
<span class="line" id="L31"> <span class="tok-kw">var</span> result: <span class="tok-type">u32</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L32"> <span class="tok-kw">for</span> (magic, <span class="tok-number">0</span>..) |character, index| {</span>
<span class="line" id="L33"> result |= (<span class="tok-builtin">@as</span>(<span class="tok-type">u32</span>, character) &lt;&lt; <span class="tok-builtin">@intCast</span>((magic.len - <span class="tok-number">1</span> - index) * <span class="tok-number">8</span>));</span>
<span class="line" id="L34"> }</span>
<span class="line" id="L35"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L36">}</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"><span class="tok-kw">pub</span> <span class="tok-kw">inline</span> <span class="tok-kw">fn</span> <span class="tok-fn">toMagicNumber</span>(magic: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, <span class="tok-kw">comptime</span> wanted_endian: std.builtin.Endian) <span class="tok-type">u32</span> {</span>
<span class="line" id="L39"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (native_endian) {</span>
<span class="line" id="L40"> .little =&gt; {</span>
<span class="line" id="L41"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (wanted_endian) {</span>
<span class="line" id="L42"> .little =&gt; toMagicNumberNative(magic),</span>
<span class="line" id="L43"> .big =&gt; toMagicNumberForeign(magic),</span>
<span class="line" id="L44"> };</span>
<span class="line" id="L45"> },</span>
<span class="line" id="L46"> .big =&gt; {</span>
<span class="line" id="L47"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (wanted_endian) {</span>
<span class="line" id="L48"> .little =&gt; toMagicNumberForeign(magic),</span>
<span class="line" id="L49"> .big =&gt; toMagicNumberNative(magic),</span>
<span class="line" id="L50"> };</span>
<span class="line" id="L51"> },</span>
<span class="line" id="L52"> };</span>
<span class="line" id="L53">}</span>
<span class="line" id="L54"></span>
<span class="line" id="L55"><span class="tok-kw">fn</span> <span class="tok-fn">checkEnumFields</span>(data: <span class="tok-kw">anytype</span>) StructReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L56"> <span class="tok-kw">const</span> T = <span class="tok-builtin">@typeInfo</span>(<span class="tok-builtin">@TypeOf</span>(data)).Pointer.child;</span>
<span class="line" id="L57"> <span class="tok-kw">inline</span> <span class="tok-kw">for</span> (std.meta.fields(T)) |entry| {</span>
<span class="line" id="L58"> <span class="tok-kw">switch</span> (<span class="tok-builtin">@typeInfo</span>(entry.<span class="tok-type">type</span>)) {</span>
<span class="line" id="L59"> .Enum =&gt; {</span>
<span class="line" id="L60"> <span class="tok-kw">const</span> value = <span class="tok-builtin">@intFromEnum</span>(<span class="tok-builtin">@field</span>(data, entry.name));</span>
<span class="line" id="L61"> _ = std.meta.intToEnum(entry.<span class="tok-type">type</span>, value) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> StructReadError.InvalidData;</span>
<span class="line" id="L62"> },</span>
<span class="line" id="L63"> .Struct =&gt; {</span>
<span class="line" id="L64"> <span class="tok-kw">try</span> checkEnumFields(&amp;<span class="tok-builtin">@field</span>(data, entry.name));</span>
<span class="line" id="L65"> },</span>
<span class="line" id="L66"> <span class="tok-kw">else</span> =&gt; {},</span>
<span class="line" id="L67"> }</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69">}</span>
<span class="line" id="L70"></span>
<span class="line" id="L71"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readStructNative</span>(reader: <span class="tok-kw">anytype</span>, <span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>) StructReadError!T {</span>
<span class="line" id="L72"> <span class="tok-kw">var</span> result: T = <span class="tok-kw">try</span> reader.readStruct(T);</span>
<span class="line" id="L73"> <span class="tok-kw">try</span> checkEnumFields(&amp;result);</span>
<span class="line" id="L74"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L75">}</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeStructNative</span>(writer: <span class="tok-kw">anytype</span>, value: <span class="tok-kw">anytype</span>) StructWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L78"> <span class="tok-kw">try</span> writer.writeStruct(value);</span>
<span class="line" id="L79">}</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeStructForeign</span>(writer: <span class="tok-kw">anytype</span>, value: <span class="tok-kw">anytype</span>) StructWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L82"> <span class="tok-kw">const</span> T = <span class="tok-builtin">@typeInfo</span>(<span class="tok-builtin">@TypeOf</span>(value));</span>
<span class="line" id="L83"> <span class="tok-kw">inline</span> <span class="tok-kw">for</span> (std.meta.fields(T)) |field| {</span>
<span class="line" id="L84"> <span class="tok-kw">switch</span> (<span class="tok-builtin">@typeInfo</span>(field.<span class="tok-type">type</span>)) {</span>
<span class="line" id="L85"> .Int =&gt; {</span>
<span class="line" id="L86"> <span class="tok-kw">try</span> writer.writeIntForeign(field.<span class="tok-type">type</span>, <span class="tok-builtin">@field</span>(value, field.name));</span>
<span class="line" id="L87"> },</span>
<span class="line" id="L88"> .Struct =&gt; {</span>
<span class="line" id="L89"> <span class="tok-kw">try</span> writeStructForeign(writer, <span class="tok-builtin">@field</span>(value, field.name));</span>
<span class="line" id="L90"> },</span>
<span class="line" id="L91"> .Enum =&gt; {</span>
<span class="line" id="L92"> <span class="tok-kw">const</span> enum_value = <span class="tok-builtin">@intFromEnum</span>(<span class="tok-builtin">@field</span>(value, field.name));</span>
<span class="line" id="L93"> <span class="tok-kw">try</span> writer.writeIntForeign(field.<span class="tok-type">type</span>, enum_value);</span>
<span class="line" id="L94"> },</span>
<span class="line" id="L95"> .Bool =&gt; {</span>
<span class="line" id="L96"> <span class="tok-kw">try</span> writer.writeByte(<span class="tok-builtin">@intFromBool</span>(<span class="tok-builtin">@field</span>(value, field.name)));</span>
<span class="line" id="L97"> },</span>
<span class="line" id="L98"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L99"> <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;Add support for type &quot;</span> ++ <span class="tok-builtin">@typeName</span>(T) ++ <span class="tok-str">&quot;.&quot;</span> ++ <span class="tok-builtin">@typeName</span>(field.<span class="tok-type">type</span>) ++ <span class="tok-str">&quot; in writeStructForeign()&quot;</span>);</span>
<span class="line" id="L100"> },</span>
<span class="line" id="L101"> }</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103">}</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"><span class="tok-comment">// Extend std.mem.byteSwapAllFields to support enums</span>
</span>
<span class="line" id="L106"><span class="tok-kw">fn</span> <span class="tok-fn">swapFieldBytes</span>(data: <span class="tok-kw">anytype</span>) StructReadError!<span class="tok-type">void</span> {</span>
<span class="line" id="L107"> <span class="tok-kw">const</span> T = <span class="tok-builtin">@typeInfo</span>(<span class="tok-builtin">@TypeOf</span>(data)).Pointer.child;</span>
<span class="line" id="L108"> <span class="tok-kw">inline</span> <span class="tok-kw">for</span> (std.meta.fields(T)) |entry| {</span>
<span class="line" id="L109"> <span class="tok-kw">switch</span> (<span class="tok-builtin">@typeInfo</span>(entry.<span class="tok-type">type</span>)) {</span>
<span class="line" id="L110"> .Int =&gt; |int| {</span>
<span class="line" id="L111"> <span class="tok-kw">if</span> (int.bits &gt; <span class="tok-number">8</span>) {</span>
<span class="line" id="L112"> <span class="tok-builtin">@field</span>(data, entry.name) = <span class="tok-builtin">@byteSwap</span>(<span class="tok-builtin">@field</span>(data, entry.name));</span>
<span class="line" id="L113"> }</span>
<span class="line" id="L114"> },</span>
<span class="line" id="L115"> .Struct =&gt; {</span>
<span class="line" id="L116"> <span class="tok-kw">try</span> swapFieldBytes(&amp;<span class="tok-builtin">@field</span>(data, entry.name));</span>
<span class="line" id="L117"> },</span>
<span class="line" id="L118"> .Enum =&gt; {</span>
<span class="line" id="L119"> <span class="tok-kw">const</span> value = <span class="tok-builtin">@intFromEnum</span>(<span class="tok-builtin">@field</span>(data, entry.name));</span>
<span class="line" id="L120"> <span class="tok-kw">if</span> (<span class="tok-builtin">@bitSizeOf</span>(<span class="tok-builtin">@TypeOf</span>(value)) &gt; <span class="tok-number">8</span>) {</span>
<span class="line" id="L121"> <span class="tok-builtin">@field</span>(data, entry.name) = <span class="tok-kw">try</span> std.meta.intToEnum(entry.<span class="tok-type">type</span>, <span class="tok-builtin">@byteSwap</span>(value));</span>
<span class="line" id="L122"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L123"> _ = std.meta.intToEnum(entry.<span class="tok-type">type</span>, value) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> StructReadError.InvalidData;</span>
<span class="line" id="L124"> }</span>
<span class="line" id="L125"> },</span>
<span class="line" id="L126"> .Array =&gt; |array| {</span>
<span class="line" id="L127"> <span class="tok-kw">if</span> (array.child != <span class="tok-type">u8</span>) {</span>
<span class="line" id="L128"> <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;Add support for type &quot;</span> ++ <span class="tok-builtin">@typeName</span>(T) ++ <span class="tok-str">&quot;.&quot;</span> ++ <span class="tok-builtin">@typeName</span>(entry.<span class="tok-type">type</span>) ++ <span class="tok-str">&quot; in swapFieldBytes&quot;</span>);</span>
<span class="line" id="L129"> }</span>
<span class="line" id="L130"> },</span>
<span class="line" id="L131"> .Bool =&gt; {},</span>
<span class="line" id="L132"> <span class="tok-kw">else</span> =&gt; {</span>
<span class="line" id="L133"> <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;Add support for type &quot;</span> ++ <span class="tok-builtin">@typeName</span>(T) ++ <span class="tok-str">&quot;.&quot;</span> ++ <span class="tok-builtin">@typeName</span>(entry.<span class="tok-type">type</span>) ++ <span class="tok-str">&quot; in swapFieldBytes&quot;</span>);</span>
<span class="line" id="L134"> },</span>
<span class="line" id="L135"> }</span>
<span class="line" id="L136"> }</span>
<span class="line" id="L137">}</span>
<span class="line" id="L138"></span>
<span class="line" id="L139"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readStructForeign</span>(reader: <span class="tok-kw">anytype</span>, <span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>) StructReadError!T {</span>
<span class="line" id="L140"> <span class="tok-kw">var</span> result: T = <span class="tok-kw">try</span> reader.readStruct(T);</span>
<span class="line" id="L141"> <span class="tok-kw">try</span> swapFieldBytes(&amp;result);</span>
<span class="line" id="L142"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L143">}</span>
<span class="line" id="L144"></span>
<span class="line" id="L145"><span class="tok-kw">pub</span> <span class="tok-kw">inline</span> <span class="tok-kw">fn</span> <span class="tok-fn">readStruct</span>(reader: <span class="tok-kw">anytype</span>, <span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>, <span class="tok-kw">comptime</span> wanted_endian: std.builtin.Endian) StructReadError!T {</span>
<span class="line" id="L146"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (native_endian) {</span>
<span class="line" id="L147"> .little =&gt; {</span>
<span class="line" id="L148"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (wanted_endian) {</span>
<span class="line" id="L149"> .little =&gt; readStructNative(reader, T),</span>
<span class="line" id="L150"> .big =&gt; readStructForeign(reader, T),</span>
<span class="line" id="L151"> };</span>
<span class="line" id="L152"> },</span>
<span class="line" id="L153"> .big =&gt; {</span>
<span class="line" id="L154"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (wanted_endian) {</span>
<span class="line" id="L155"> .little =&gt; readStructForeign(reader, T),</span>
<span class="line" id="L156"> .big =&gt; readStructNative(reader, T),</span>
<span class="line" id="L157"> };</span>
<span class="line" id="L158"> },</span>
<span class="line" id="L159"> };</span>
<span class="line" id="L160">}</span>
<span class="line" id="L161"></span>
<span class="line" id="L162"><span class="tok-kw">pub</span> <span class="tok-kw">inline</span> <span class="tok-kw">fn</span> <span class="tok-fn">writeStruct</span>(writer: <span class="tok-kw">anytype</span>, value: <span class="tok-kw">anytype</span>, <span class="tok-kw">comptime</span> wanted_endian: std.builtin.Endian) StructWriteError!<span class="tok-type">void</span> {</span>
<span class="line" id="L163"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (native_endian) {</span>
<span class="line" id="L164"> .little =&gt; {</span>
<span class="line" id="L165"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (wanted_endian) {</span>
<span class="line" id="L166"> .little =&gt; writeStructNative(writer, value),</span>
<span class="line" id="L167"> .big =&gt; writeStructForeign(writer, value),</span>
<span class="line" id="L168"> };</span>
<span class="line" id="L169"> },</span>
<span class="line" id="L170"> .big =&gt; {</span>
<span class="line" id="L171"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (wanted_endian) {</span>
<span class="line" id="L172"> .little =&gt; writeStructForeign(writer, value),</span>
<span class="line" id="L173"> .big =&gt; writeStructNative(writer, value),</span>
<span class="line" id="L174"> };</span>
<span class="line" id="L175"> },</span>
<span class="line" id="L176"> };</span>
<span class="line" id="L177">}</span>
<span class="line" id="L178"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,156 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>zigimg.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> AllFormats = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/all.zig&quot;</span>);</span>
<span class="line" id="L2"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> bmp = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/bmp.zig&quot;</span>);</span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> color = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/color.zig&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> FormatInterface = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/FormatInterface.zig&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Image = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/Image.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> gif = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/gif.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> netpbm = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/netpbm.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> OctTreeQuantizer = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/octree_quantizer.zig&quot;</span>).OctTreeQuantizer;</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> pcx = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/pcx.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> PixelFormat = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/pixel_format.zig&quot;</span>).PixelFormat;</span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> jpeg = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/jpeg.zig&quot;</span>);</span>
<span class="line" id="L12"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> png = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/png.zig&quot;</span>);</span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> qoi = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/qoi.zig&quot;</span>);</span>
<span class="line" id="L14"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> tga = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/tga.zig&quot;</span>);</span>
<span class="line" id="L15"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> pam = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/pam.zig&quot;</span>);</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"><span class="tok-kw">test</span> {</span>
<span class="line" id="L18"> <span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L19"> std.testing.refAllDecls(<span class="tok-builtin">@This</span>());</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"> <span class="tok-kw">inline</span> <span class="tok-kw">for</span> (.{</span>
<span class="line" id="L22"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/compressions/lzw.zig&quot;</span>),</span>
<span class="line" id="L23"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;src/formats/png/reader.zig&quot;</span>),</span>
<span class="line" id="L24"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/buffered_stream_source_test.zig&quot;</span>),</span>
<span class="line" id="L25"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/color_test.zig&quot;</span>),</span>
<span class="line" id="L26"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/bmp_test.zig&quot;</span>),</span>
<span class="line" id="L27"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/gif_test.zig&quot;</span>),</span>
<span class="line" id="L28"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/jpeg_test.zig&quot;</span>),</span>
<span class="line" id="L29"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/netpbm_test.zig&quot;</span>),</span>
<span class="line" id="L30"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/pam_test.zig&quot;</span>),</span>
<span class="line" id="L31"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/pcx_test.zig&quot;</span>),</span>
<span class="line" id="L32"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/png_test.zig&quot;</span>),</span>
<span class="line" id="L33"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/qoi_test.zig&quot;</span>),</span>
<span class="line" id="L34"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/formats/tga_test.zig&quot;</span>),</span>
<span class="line" id="L35"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/image_test.zig&quot;</span>),</span>
<span class="line" id="L36"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/octree_quantizer_test.zig&quot;</span>),</span>
<span class="line" id="L37"> <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;tests/pixel_format_test.zig&quot;</span>),</span>
<span class="line" id="L38"> }) |source_file| std.testing.refAllDeclsRecursive(source_file);</span>
<span class="line" id="L39">}</span>
<span class="line" id="L40"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,519 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>autogen/derived_combining_class.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Autogenerated from https://www.unicode.org/Public/15.0.0/ucd/</span>
</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-comment">// `combiningClass` maps the code point to its combining class value.</span>
</span>
<span class="line" id="L4"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">combiningClass</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u8</span> {</span>
<span class="line" id="L5"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (cp) {</span>
<span class="line" id="L6"> <span class="tok-number">0x334</span>...<span class="tok-number">0x338</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L7"> <span class="tok-number">0x1CD4</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L8"> <span class="tok-number">0x1CE2</span>...<span class="tok-number">0x1CE8</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L9"> <span class="tok-number">0x20D2</span>...<span class="tok-number">0x20D3</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L10"> <span class="tok-number">0x20D8</span>...<span class="tok-number">0x20DA</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L11"> <span class="tok-number">0x20E5</span>...<span class="tok-number">0x20E6</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L12"> <span class="tok-number">0x20EA</span>...<span class="tok-number">0x20EB</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L13"> <span class="tok-number">0x10A39</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L14"> <span class="tok-number">0x16AF0</span>...<span class="tok-number">0x16AF4</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L15"> <span class="tok-number">0x1BC9E</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L16"> <span class="tok-number">0x1D167</span>...<span class="tok-number">0x1D169</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L17"> <span class="tok-number">0x16FF0</span>...<span class="tok-number">0x16FF1</span> =&gt; <span class="tok-number">6</span>,</span>
<span class="line" id="L18"> <span class="tok-number">0x93C</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L19"> <span class="tok-number">0x9BC</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L20"> <span class="tok-number">0xA3C</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L21"> <span class="tok-number">0xABC</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L22"> <span class="tok-number">0xB3C</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L23"> <span class="tok-number">0xC3C</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L24"> <span class="tok-number">0xCBC</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L25"> <span class="tok-number">0x1037</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L26"> <span class="tok-number">0x1B34</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L27"> <span class="tok-number">0x1BE6</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L28"> <span class="tok-number">0x1C37</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L29"> <span class="tok-number">0xA9B3</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L30"> <span class="tok-number">0x110BA</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L31"> <span class="tok-number">0x11173</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L32"> <span class="tok-number">0x111CA</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L33"> <span class="tok-number">0x11236</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L34"> <span class="tok-number">0x112E9</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L35"> <span class="tok-number">0x1133B</span>...<span class="tok-number">0x1133C</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L36"> <span class="tok-number">0x11446</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L37"> <span class="tok-number">0x114C3</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L38"> <span class="tok-number">0x115C0</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L39"> <span class="tok-number">0x116B7</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L40"> <span class="tok-number">0x1183A</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L41"> <span class="tok-number">0x11943</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L42"> <span class="tok-number">0x11D42</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L43"> <span class="tok-number">0x1E94A</span> =&gt; <span class="tok-number">7</span>,</span>
<span class="line" id="L44"> <span class="tok-number">0x3099</span>...<span class="tok-number">0x309A</span> =&gt; <span class="tok-number">8</span>,</span>
<span class="line" id="L45"> <span class="tok-number">0x94D</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L46"> <span class="tok-number">0x9CD</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L47"> <span class="tok-number">0xA4D</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L48"> <span class="tok-number">0xACD</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L49"> <span class="tok-number">0xB4D</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L50"> <span class="tok-number">0xBCD</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L51"> <span class="tok-number">0xC4D</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L52"> <span class="tok-number">0xCCD</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L53"> <span class="tok-number">0xD3B</span>...<span class="tok-number">0xD3C</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L54"> <span class="tok-number">0xD4D</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L55"> <span class="tok-number">0xDCA</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L56"> <span class="tok-number">0xE3A</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L57"> <span class="tok-number">0xEBA</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L58"> <span class="tok-number">0xF84</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L59"> <span class="tok-number">0x1039</span>...<span class="tok-number">0x103A</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L60"> <span class="tok-number">0x1714</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L61"> <span class="tok-number">0x1715</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L62"> <span class="tok-number">0x1734</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L63"> <span class="tok-number">0x17D2</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L64"> <span class="tok-number">0x1A60</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L65"> <span class="tok-number">0x1B44</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L66"> <span class="tok-number">0x1BAA</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L67"> <span class="tok-number">0x1BAB</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L68"> <span class="tok-number">0x1BF2</span>...<span class="tok-number">0x1BF3</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L69"> <span class="tok-number">0x2D7F</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L70"> <span class="tok-number">0xA806</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L71"> <span class="tok-number">0xA82C</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L72"> <span class="tok-number">0xA8C4</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L73"> <span class="tok-number">0xA953</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L74"> <span class="tok-number">0xA9C0</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L75"> <span class="tok-number">0xAAF6</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L76"> <span class="tok-number">0xABED</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L77"> <span class="tok-number">0x10A3F</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L78"> <span class="tok-number">0x11046</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L79"> <span class="tok-number">0x11070</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L80"> <span class="tok-number">0x1107F</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L81"> <span class="tok-number">0x110B9</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L82"> <span class="tok-number">0x11133</span>...<span class="tok-number">0x11134</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L83"> <span class="tok-number">0x111C0</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L84"> <span class="tok-number">0x11235</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L85"> <span class="tok-number">0x112EA</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L86"> <span class="tok-number">0x1134D</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L87"> <span class="tok-number">0x11442</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L88"> <span class="tok-number">0x114C2</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L89"> <span class="tok-number">0x115BF</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L90"> <span class="tok-number">0x1163F</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L91"> <span class="tok-number">0x116B6</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L92"> <span class="tok-number">0x1172B</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L93"> <span class="tok-number">0x11839</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L94"> <span class="tok-number">0x1193D</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L95"> <span class="tok-number">0x1193E</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L96"> <span class="tok-number">0x119E0</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L97"> <span class="tok-number">0x11A34</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L98"> <span class="tok-number">0x11A47</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L99"> <span class="tok-number">0x11A99</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L100"> <span class="tok-number">0x11C3F</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L101"> <span class="tok-number">0x11D44</span>...<span class="tok-number">0x11D45</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L102"> <span class="tok-number">0x11D97</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L103"> <span class="tok-number">0x11F41</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L104"> <span class="tok-number">0x11F42</span> =&gt; <span class="tok-number">9</span>,</span>
<span class="line" id="L105"> <span class="tok-number">0x5B0</span> =&gt; <span class="tok-number">10</span>,</span>
<span class="line" id="L106"> <span class="tok-number">0x5B1</span> =&gt; <span class="tok-number">11</span>,</span>
<span class="line" id="L107"> <span class="tok-number">0x5B2</span> =&gt; <span class="tok-number">12</span>,</span>
<span class="line" id="L108"> <span class="tok-number">0x5B3</span> =&gt; <span class="tok-number">13</span>,</span>
<span class="line" id="L109"> <span class="tok-number">0x5B4</span> =&gt; <span class="tok-number">14</span>,</span>
<span class="line" id="L110"> <span class="tok-number">0x5B5</span> =&gt; <span class="tok-number">15</span>,</span>
<span class="line" id="L111"> <span class="tok-number">0x5B6</span> =&gt; <span class="tok-number">16</span>,</span>
<span class="line" id="L112"> <span class="tok-number">0x5B7</span> =&gt; <span class="tok-number">17</span>,</span>
<span class="line" id="L113"> <span class="tok-number">0x5B8</span> =&gt; <span class="tok-number">18</span>,</span>
<span class="line" id="L114"> <span class="tok-number">0x5C7</span> =&gt; <span class="tok-number">18</span>,</span>
<span class="line" id="L115"> <span class="tok-number">0x5B9</span>...<span class="tok-number">0x5BA</span> =&gt; <span class="tok-number">19</span>,</span>
<span class="line" id="L116"> <span class="tok-number">0x5BB</span> =&gt; <span class="tok-number">20</span>,</span>
<span class="line" id="L117"> <span class="tok-number">0x5BC</span> =&gt; <span class="tok-number">21</span>,</span>
<span class="line" id="L118"> <span class="tok-number">0x5BD</span> =&gt; <span class="tok-number">22</span>,</span>
<span class="line" id="L119"> <span class="tok-number">0x5BF</span> =&gt; <span class="tok-number">23</span>,</span>
<span class="line" id="L120"> <span class="tok-number">0x5C1</span> =&gt; <span class="tok-number">24</span>,</span>
<span class="line" id="L121"> <span class="tok-number">0x5C2</span> =&gt; <span class="tok-number">25</span>,</span>
<span class="line" id="L122"> <span class="tok-number">0xFB1E</span> =&gt; <span class="tok-number">26</span>,</span>
<span class="line" id="L123"> <span class="tok-number">0x64B</span> =&gt; <span class="tok-number">27</span>,</span>
<span class="line" id="L124"> <span class="tok-number">0x8F0</span> =&gt; <span class="tok-number">27</span>,</span>
<span class="line" id="L125"> <span class="tok-number">0x64C</span> =&gt; <span class="tok-number">28</span>,</span>
<span class="line" id="L126"> <span class="tok-number">0x8F1</span> =&gt; <span class="tok-number">28</span>,</span>
<span class="line" id="L127"> <span class="tok-number">0x64D</span> =&gt; <span class="tok-number">29</span>,</span>
<span class="line" id="L128"> <span class="tok-number">0x8F2</span> =&gt; <span class="tok-number">29</span>,</span>
<span class="line" id="L129"> <span class="tok-number">0x618</span> =&gt; <span class="tok-number">30</span>,</span>
<span class="line" id="L130"> <span class="tok-number">0x64E</span> =&gt; <span class="tok-number">30</span>,</span>
<span class="line" id="L131"> <span class="tok-number">0x619</span> =&gt; <span class="tok-number">31</span>,</span>
<span class="line" id="L132"> <span class="tok-number">0x64F</span> =&gt; <span class="tok-number">31</span>,</span>
<span class="line" id="L133"> <span class="tok-number">0x61A</span> =&gt; <span class="tok-number">32</span>,</span>
<span class="line" id="L134"> <span class="tok-number">0x650</span> =&gt; <span class="tok-number">32</span>,</span>
<span class="line" id="L135"> <span class="tok-number">0x651</span> =&gt; <span class="tok-number">33</span>,</span>
<span class="line" id="L136"> <span class="tok-number">0x652</span> =&gt; <span class="tok-number">34</span>,</span>
<span class="line" id="L137"> <span class="tok-number">0x670</span> =&gt; <span class="tok-number">35</span>,</span>
<span class="line" id="L138"> <span class="tok-number">0x711</span> =&gt; <span class="tok-number">36</span>,</span>
<span class="line" id="L139"> <span class="tok-number">0xC55</span> =&gt; <span class="tok-number">84</span>,</span>
<span class="line" id="L140"> <span class="tok-number">0xC56</span> =&gt; <span class="tok-number">91</span>,</span>
<span class="line" id="L141"> <span class="tok-number">0xE38</span>...<span class="tok-number">0xE39</span> =&gt; <span class="tok-number">103</span>,</span>
<span class="line" id="L142"> <span class="tok-number">0xE48</span>...<span class="tok-number">0xE4B</span> =&gt; <span class="tok-number">107</span>,</span>
<span class="line" id="L143"> <span class="tok-number">0xEB8</span>...<span class="tok-number">0xEB9</span> =&gt; <span class="tok-number">118</span>,</span>
<span class="line" id="L144"> <span class="tok-number">0xEC8</span>...<span class="tok-number">0xECB</span> =&gt; <span class="tok-number">122</span>,</span>
<span class="line" id="L145"> <span class="tok-number">0xF71</span> =&gt; <span class="tok-number">129</span>,</span>
<span class="line" id="L146"> <span class="tok-number">0xF72</span> =&gt; <span class="tok-number">130</span>,</span>
<span class="line" id="L147"> <span class="tok-number">0xF7A</span>...<span class="tok-number">0xF7D</span> =&gt; <span class="tok-number">130</span>,</span>
<span class="line" id="L148"> <span class="tok-number">0xF80</span> =&gt; <span class="tok-number">130</span>,</span>
<span class="line" id="L149"> <span class="tok-number">0xF74</span> =&gt; <span class="tok-number">132</span>,</span>
<span class="line" id="L150"> <span class="tok-number">0x321</span>...<span class="tok-number">0x322</span> =&gt; <span class="tok-number">202</span>,</span>
<span class="line" id="L151"> <span class="tok-number">0x327</span>...<span class="tok-number">0x328</span> =&gt; <span class="tok-number">202</span>,</span>
<span class="line" id="L152"> <span class="tok-number">0x1DD0</span> =&gt; <span class="tok-number">202</span>,</span>
<span class="line" id="L153"> <span class="tok-number">0x1DCE</span> =&gt; <span class="tok-number">214</span>,</span>
<span class="line" id="L154"> <span class="tok-number">0x31B</span> =&gt; <span class="tok-number">216</span>,</span>
<span class="line" id="L155"> <span class="tok-number">0xF39</span> =&gt; <span class="tok-number">216</span>,</span>
<span class="line" id="L156"> <span class="tok-number">0x1D165</span>...<span class="tok-number">0x1D166</span> =&gt; <span class="tok-number">216</span>,</span>
<span class="line" id="L157"> <span class="tok-number">0x1D16E</span>...<span class="tok-number">0x1D172</span> =&gt; <span class="tok-number">216</span>,</span>
<span class="line" id="L158"> <span class="tok-number">0x1DFA</span> =&gt; <span class="tok-number">218</span>,</span>
<span class="line" id="L159"> <span class="tok-number">0x302A</span> =&gt; <span class="tok-number">218</span>,</span>
<span class="line" id="L160"> <span class="tok-number">0x316</span>...<span class="tok-number">0x319</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L161"> <span class="tok-number">0x31C</span>...<span class="tok-number">0x320</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L162"> <span class="tok-number">0x323</span>...<span class="tok-number">0x326</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L163"> <span class="tok-number">0x329</span>...<span class="tok-number">0x333</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L164"> <span class="tok-number">0x339</span>...<span class="tok-number">0x33C</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L165"> <span class="tok-number">0x347</span>...<span class="tok-number">0x349</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L166"> <span class="tok-number">0x34D</span>...<span class="tok-number">0x34E</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L167"> <span class="tok-number">0x353</span>...<span class="tok-number">0x356</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L168"> <span class="tok-number">0x359</span>...<span class="tok-number">0x35A</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L169"> <span class="tok-number">0x591</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L170"> <span class="tok-number">0x596</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L171"> <span class="tok-number">0x59B</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L172"> <span class="tok-number">0x5A2</span>...<span class="tok-number">0x5A7</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L173"> <span class="tok-number">0x5AA</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L174"> <span class="tok-number">0x5C5</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L175"> <span class="tok-number">0x655</span>...<span class="tok-number">0x656</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L176"> <span class="tok-number">0x65C</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L177"> <span class="tok-number">0x65F</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L178"> <span class="tok-number">0x6E3</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L179"> <span class="tok-number">0x6EA</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L180"> <span class="tok-number">0x6ED</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L181"> <span class="tok-number">0x731</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L182"> <span class="tok-number">0x734</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L183"> <span class="tok-number">0x737</span>...<span class="tok-number">0x739</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L184"> <span class="tok-number">0x73B</span>...<span class="tok-number">0x73C</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L185"> <span class="tok-number">0x73E</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L186"> <span class="tok-number">0x742</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L187"> <span class="tok-number">0x744</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L188"> <span class="tok-number">0x746</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L189"> <span class="tok-number">0x748</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L190"> <span class="tok-number">0x7F2</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L191"> <span class="tok-number">0x7FD</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L192"> <span class="tok-number">0x859</span>...<span class="tok-number">0x85B</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L193"> <span class="tok-number">0x899</span>...<span class="tok-number">0x89B</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L194"> <span class="tok-number">0x8CF</span>...<span class="tok-number">0x8D3</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L195"> <span class="tok-number">0x8E3</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L196"> <span class="tok-number">0x8E6</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L197"> <span class="tok-number">0x8E9</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L198"> <span class="tok-number">0x8ED</span>...<span class="tok-number">0x8EF</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L199"> <span class="tok-number">0x8F6</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L200"> <span class="tok-number">0x8F9</span>...<span class="tok-number">0x8FA</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L201"> <span class="tok-number">0x952</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L202"> <span class="tok-number">0xF18</span>...<span class="tok-number">0xF19</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L203"> <span class="tok-number">0xF35</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L204"> <span class="tok-number">0xF37</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L205"> <span class="tok-number">0xFC6</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L206"> <span class="tok-number">0x108D</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L207"> <span class="tok-number">0x193B</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L208"> <span class="tok-number">0x1A18</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L209"> <span class="tok-number">0x1A7F</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L210"> <span class="tok-number">0x1AB5</span>...<span class="tok-number">0x1ABA</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L211"> <span class="tok-number">0x1ABD</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L212"> <span class="tok-number">0x1ABF</span>...<span class="tok-number">0x1AC0</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L213"> <span class="tok-number">0x1AC3</span>...<span class="tok-number">0x1AC4</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L214"> <span class="tok-number">0x1ACA</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L215"> <span class="tok-number">0x1B6C</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L216"> <span class="tok-number">0x1CD5</span>...<span class="tok-number">0x1CD9</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L217"> <span class="tok-number">0x1CDC</span>...<span class="tok-number">0x1CDF</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L218"> <span class="tok-number">0x1CED</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L219"> <span class="tok-number">0x1DC2</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L220"> <span class="tok-number">0x1DCA</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L221"> <span class="tok-number">0x1DCF</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L222"> <span class="tok-number">0x1DF9</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L223"> <span class="tok-number">0x1DFD</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L224"> <span class="tok-number">0x1DFF</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L225"> <span class="tok-number">0x20E8</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L226"> <span class="tok-number">0x20EC</span>...<span class="tok-number">0x20EF</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L227"> <span class="tok-number">0xA92B</span>...<span class="tok-number">0xA92D</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L228"> <span class="tok-number">0xAAB4</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L229"> <span class="tok-number">0xFE27</span>...<span class="tok-number">0xFE2D</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L230"> <span class="tok-number">0x101FD</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L231"> <span class="tok-number">0x102E0</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L232"> <span class="tok-number">0x10A0D</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L233"> <span class="tok-number">0x10A3A</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L234"> <span class="tok-number">0x10AE6</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L235"> <span class="tok-number">0x10EFD</span>...<span class="tok-number">0x10EFF</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L236"> <span class="tok-number">0x10F46</span>...<span class="tok-number">0x10F47</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L237"> <span class="tok-number">0x10F4B</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L238"> <span class="tok-number">0x10F4D</span>...<span class="tok-number">0x10F50</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L239"> <span class="tok-number">0x10F83</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L240"> <span class="tok-number">0x10F85</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L241"> <span class="tok-number">0x1D17B</span>...<span class="tok-number">0x1D182</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L242"> <span class="tok-number">0x1D18A</span>...<span class="tok-number">0x1D18B</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L243"> <span class="tok-number">0x1E4EE</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L244"> <span class="tok-number">0x1E8D0</span>...<span class="tok-number">0x1E8D6</span> =&gt; <span class="tok-number">220</span>,</span>
<span class="line" id="L245"> <span class="tok-number">0x59A</span> =&gt; <span class="tok-number">222</span>,</span>
<span class="line" id="L246"> <span class="tok-number">0x5AD</span> =&gt; <span class="tok-number">222</span>,</span>
<span class="line" id="L247"> <span class="tok-number">0x1939</span> =&gt; <span class="tok-number">222</span>,</span>
<span class="line" id="L248"> <span class="tok-number">0x302D</span> =&gt; <span class="tok-number">222</span>,</span>
<span class="line" id="L249"> <span class="tok-number">0x302E</span>...<span class="tok-number">0x302F</span> =&gt; <span class="tok-number">224</span>,</span>
<span class="line" id="L250"> <span class="tok-number">0x1D16D</span> =&gt; <span class="tok-number">226</span>,</span>
<span class="line" id="L251"> <span class="tok-number">0x5AE</span> =&gt; <span class="tok-number">228</span>,</span>
<span class="line" id="L252"> <span class="tok-number">0x18A9</span> =&gt; <span class="tok-number">228</span>,</span>
<span class="line" id="L253"> <span class="tok-number">0x1DF7</span>...<span class="tok-number">0x1DF8</span> =&gt; <span class="tok-number">228</span>,</span>
<span class="line" id="L254"> <span class="tok-number">0x302B</span> =&gt; <span class="tok-number">228</span>,</span>
<span class="line" id="L255"> <span class="tok-number">0x300</span>...<span class="tok-number">0x314</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L256"> <span class="tok-number">0x33D</span>...<span class="tok-number">0x344</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L257"> <span class="tok-number">0x346</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L258"> <span class="tok-number">0x34A</span>...<span class="tok-number">0x34C</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L259"> <span class="tok-number">0x350</span>...<span class="tok-number">0x352</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L260"> <span class="tok-number">0x357</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L261"> <span class="tok-number">0x35B</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L262"> <span class="tok-number">0x363</span>...<span class="tok-number">0x36F</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L263"> <span class="tok-number">0x483</span>...<span class="tok-number">0x487</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L264"> <span class="tok-number">0x592</span>...<span class="tok-number">0x595</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L265"> <span class="tok-number">0x597</span>...<span class="tok-number">0x599</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L266"> <span class="tok-number">0x59C</span>...<span class="tok-number">0x5A1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L267"> <span class="tok-number">0x5A8</span>...<span class="tok-number">0x5A9</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L268"> <span class="tok-number">0x5AB</span>...<span class="tok-number">0x5AC</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L269"> <span class="tok-number">0x5AF</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L270"> <span class="tok-number">0x5C4</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L271"> <span class="tok-number">0x610</span>...<span class="tok-number">0x617</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L272"> <span class="tok-number">0x653</span>...<span class="tok-number">0x654</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L273"> <span class="tok-number">0x657</span>...<span class="tok-number">0x65B</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L274"> <span class="tok-number">0x65D</span>...<span class="tok-number">0x65E</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L275"> <span class="tok-number">0x6D6</span>...<span class="tok-number">0x6DC</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L276"> <span class="tok-number">0x6DF</span>...<span class="tok-number">0x6E2</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L277"> <span class="tok-number">0x6E4</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L278"> <span class="tok-number">0x6E7</span>...<span class="tok-number">0x6E8</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L279"> <span class="tok-number">0x6EB</span>...<span class="tok-number">0x6EC</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L280"> <span class="tok-number">0x730</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L281"> <span class="tok-number">0x732</span>...<span class="tok-number">0x733</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L282"> <span class="tok-number">0x735</span>...<span class="tok-number">0x736</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L283"> <span class="tok-number">0x73A</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L284"> <span class="tok-number">0x73D</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L285"> <span class="tok-number">0x73F</span>...<span class="tok-number">0x741</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L286"> <span class="tok-number">0x743</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L287"> <span class="tok-number">0x745</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L288"> <span class="tok-number">0x747</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L289"> <span class="tok-number">0x749</span>...<span class="tok-number">0x74A</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L290"> <span class="tok-number">0x7EB</span>...<span class="tok-number">0x7F1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L291"> <span class="tok-number">0x7F3</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L292"> <span class="tok-number">0x816</span>...<span class="tok-number">0x819</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L293"> <span class="tok-number">0x81B</span>...<span class="tok-number">0x823</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L294"> <span class="tok-number">0x825</span>...<span class="tok-number">0x827</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L295"> <span class="tok-number">0x829</span>...<span class="tok-number">0x82D</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L296"> <span class="tok-number">0x898</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L297"> <span class="tok-number">0x89C</span>...<span class="tok-number">0x89F</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L298"> <span class="tok-number">0x8CA</span>...<span class="tok-number">0x8CE</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L299"> <span class="tok-number">0x8D4</span>...<span class="tok-number">0x8E1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L300"> <span class="tok-number">0x8E4</span>...<span class="tok-number">0x8E5</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L301"> <span class="tok-number">0x8E7</span>...<span class="tok-number">0x8E8</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L302"> <span class="tok-number">0x8EA</span>...<span class="tok-number">0x8EC</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L303"> <span class="tok-number">0x8F3</span>...<span class="tok-number">0x8F5</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L304"> <span class="tok-number">0x8F7</span>...<span class="tok-number">0x8F8</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L305"> <span class="tok-number">0x8FB</span>...<span class="tok-number">0x8FF</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L306"> <span class="tok-number">0x951</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L307"> <span class="tok-number">0x953</span>...<span class="tok-number">0x954</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L308"> <span class="tok-number">0x9FE</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L309"> <span class="tok-number">0xF82</span>...<span class="tok-number">0xF83</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L310"> <span class="tok-number">0xF86</span>...<span class="tok-number">0xF87</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L311"> <span class="tok-number">0x135D</span>...<span class="tok-number">0x135F</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L312"> <span class="tok-number">0x17DD</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L313"> <span class="tok-number">0x193A</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L314"> <span class="tok-number">0x1A17</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L315"> <span class="tok-number">0x1A75</span>...<span class="tok-number">0x1A7C</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L316"> <span class="tok-number">0x1AB0</span>...<span class="tok-number">0x1AB4</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L317"> <span class="tok-number">0x1ABB</span>...<span class="tok-number">0x1ABC</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L318"> <span class="tok-number">0x1AC1</span>...<span class="tok-number">0x1AC2</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L319"> <span class="tok-number">0x1AC5</span>...<span class="tok-number">0x1AC9</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L320"> <span class="tok-number">0x1ACB</span>...<span class="tok-number">0x1ACE</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L321"> <span class="tok-number">0x1B6B</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L322"> <span class="tok-number">0x1B6D</span>...<span class="tok-number">0x1B73</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L323"> <span class="tok-number">0x1CD0</span>...<span class="tok-number">0x1CD2</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L324"> <span class="tok-number">0x1CDA</span>...<span class="tok-number">0x1CDB</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L325"> <span class="tok-number">0x1CE0</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L326"> <span class="tok-number">0x1CF4</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L327"> <span class="tok-number">0x1CF8</span>...<span class="tok-number">0x1CF9</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L328"> <span class="tok-number">0x1DC0</span>...<span class="tok-number">0x1DC1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L329"> <span class="tok-number">0x1DC3</span>...<span class="tok-number">0x1DC9</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L330"> <span class="tok-number">0x1DCB</span>...<span class="tok-number">0x1DCC</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L331"> <span class="tok-number">0x1DD1</span>...<span class="tok-number">0x1DF5</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L332"> <span class="tok-number">0x1DFB</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L333"> <span class="tok-number">0x1DFE</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L334"> <span class="tok-number">0x20D0</span>...<span class="tok-number">0x20D1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L335"> <span class="tok-number">0x20D4</span>...<span class="tok-number">0x20D7</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L336"> <span class="tok-number">0x20DB</span>...<span class="tok-number">0x20DC</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L337"> <span class="tok-number">0x20E1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L338"> <span class="tok-number">0x20E7</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L339"> <span class="tok-number">0x20E9</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L340"> <span class="tok-number">0x20F0</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L341"> <span class="tok-number">0x2CEF</span>...<span class="tok-number">0x2CF1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L342"> <span class="tok-number">0x2DE0</span>...<span class="tok-number">0x2DFF</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L343"> <span class="tok-number">0xA66F</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L344"> <span class="tok-number">0xA674</span>...<span class="tok-number">0xA67D</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L345"> <span class="tok-number">0xA69E</span>...<span class="tok-number">0xA69F</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L346"> <span class="tok-number">0xA6F0</span>...<span class="tok-number">0xA6F1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L347"> <span class="tok-number">0xA8E0</span>...<span class="tok-number">0xA8F1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L348"> <span class="tok-number">0xAAB0</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L349"> <span class="tok-number">0xAAB2</span>...<span class="tok-number">0xAAB3</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L350"> <span class="tok-number">0xAAB7</span>...<span class="tok-number">0xAAB8</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L351"> <span class="tok-number">0xAABE</span>...<span class="tok-number">0xAABF</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L352"> <span class="tok-number">0xAAC1</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L353"> <span class="tok-number">0xFE20</span>...<span class="tok-number">0xFE26</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L354"> <span class="tok-number">0xFE2E</span>...<span class="tok-number">0xFE2F</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L355"> <span class="tok-number">0x10376</span>...<span class="tok-number">0x1037A</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L356"> <span class="tok-number">0x10A0F</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L357"> <span class="tok-number">0x10A38</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L358"> <span class="tok-number">0x10AE5</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L359"> <span class="tok-number">0x10D24</span>...<span class="tok-number">0x10D27</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L360"> <span class="tok-number">0x10EAB</span>...<span class="tok-number">0x10EAC</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L361"> <span class="tok-number">0x10F48</span>...<span class="tok-number">0x10F4A</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L362"> <span class="tok-number">0x10F4C</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L363"> <span class="tok-number">0x10F82</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L364"> <span class="tok-number">0x10F84</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L365"> <span class="tok-number">0x11100</span>...<span class="tok-number">0x11102</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L366"> <span class="tok-number">0x11366</span>...<span class="tok-number">0x1136C</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L367"> <span class="tok-number">0x11370</span>...<span class="tok-number">0x11374</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L368"> <span class="tok-number">0x1145E</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L369"> <span class="tok-number">0x16B30</span>...<span class="tok-number">0x16B36</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L370"> <span class="tok-number">0x1D185</span>...<span class="tok-number">0x1D189</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L371"> <span class="tok-number">0x1D1AA</span>...<span class="tok-number">0x1D1AD</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L372"> <span class="tok-number">0x1D242</span>...<span class="tok-number">0x1D244</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L373"> <span class="tok-number">0x1E000</span>...<span class="tok-number">0x1E006</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L374"> <span class="tok-number">0x1E008</span>...<span class="tok-number">0x1E018</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L375"> <span class="tok-number">0x1E01B</span>...<span class="tok-number">0x1E021</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L376"> <span class="tok-number">0x1E023</span>...<span class="tok-number">0x1E024</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L377"> <span class="tok-number">0x1E026</span>...<span class="tok-number">0x1E02A</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L378"> <span class="tok-number">0x1E08F</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L379"> <span class="tok-number">0x1E130</span>...<span class="tok-number">0x1E136</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L380"> <span class="tok-number">0x1E2AE</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L381"> <span class="tok-number">0x1E2EC</span>...<span class="tok-number">0x1E2EF</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L382"> <span class="tok-number">0x1E4EF</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L383"> <span class="tok-number">0x1E944</span>...<span class="tok-number">0x1E949</span> =&gt; <span class="tok-number">230</span>,</span>
<span class="line" id="L384"> <span class="tok-number">0x315</span> =&gt; <span class="tok-number">232</span>,</span>
<span class="line" id="L385"> <span class="tok-number">0x31A</span> =&gt; <span class="tok-number">232</span>,</span>
<span class="line" id="L386"> <span class="tok-number">0x358</span> =&gt; <span class="tok-number">232</span>,</span>
<span class="line" id="L387"> <span class="tok-number">0x1DF6</span> =&gt; <span class="tok-number">232</span>,</span>
<span class="line" id="L388"> <span class="tok-number">0x302C</span> =&gt; <span class="tok-number">232</span>,</span>
<span class="line" id="L389"> <span class="tok-number">0x1E4EC</span>...<span class="tok-number">0x1E4ED</span> =&gt; <span class="tok-number">232</span>,</span>
<span class="line" id="L390"> <span class="tok-number">0x35C</span> =&gt; <span class="tok-number">233</span>,</span>
<span class="line" id="L391"> <span class="tok-number">0x35F</span> =&gt; <span class="tok-number">233</span>,</span>
<span class="line" id="L392"> <span class="tok-number">0x362</span> =&gt; <span class="tok-number">233</span>,</span>
<span class="line" id="L393"> <span class="tok-number">0x1DFC</span> =&gt; <span class="tok-number">233</span>,</span>
<span class="line" id="L394"> <span class="tok-number">0x35D</span>...<span class="tok-number">0x35E</span> =&gt; <span class="tok-number">234</span>,</span>
<span class="line" id="L395"> <span class="tok-number">0x360</span>...<span class="tok-number">0x361</span> =&gt; <span class="tok-number">234</span>,</span>
<span class="line" id="L396"> <span class="tok-number">0x1DCD</span> =&gt; <span class="tok-number">234</span>,</span>
<span class="line" id="L397"> <span class="tok-number">0x345</span> =&gt; <span class="tok-number">240</span>,</span>
<span class="line" id="L398"> <span class="tok-kw">else</span> =&gt; <span class="tok-number">0</span>,</span>
<span class="line" id="L399"> };</span>
<span class="line" id="L400">}</span>
<span class="line" id="L401"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,382 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>autogen/derived_numeric_type.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Autogenerated from https://www.unicode.org/Public/15.0.0/ucd/</span>
</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isNumeric</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L4"> <span class="tok-kw">if</span> (cp &lt; <span class="tok-number">0xbc</span> <span class="tok-kw">or</span> cp &gt; <span class="tok-number">0x2f890</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (cp) {</span>
<span class="line" id="L7"> <span class="tok-number">0xbc</span>...<span class="tok-number">0xbe</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L8"> <span class="tok-number">0x9f4</span>...<span class="tok-number">0x9f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L9"> <span class="tok-number">0xb72</span>...<span class="tok-number">0xb77</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L10"> <span class="tok-number">0xbf0</span>...<span class="tok-number">0xbf2</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L11"> <span class="tok-number">0xc78</span>...<span class="tok-number">0xc7e</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L12"> <span class="tok-number">0xd58</span>...<span class="tok-number">0xd5e</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L13"> <span class="tok-number">0xd70</span>...<span class="tok-number">0xd78</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L14"> <span class="tok-number">0xf2a</span>...<span class="tok-number">0xf33</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L15"> <span class="tok-number">0x1372</span>...<span class="tok-number">0x137c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L16"> <span class="tok-number">0x16ee</span>...<span class="tok-number">0x16f0</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L17"> <span class="tok-number">0x17f0</span>...<span class="tok-number">0x17f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L18"> <span class="tok-number">0x2150</span>...<span class="tok-number">0x215f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L19"> <span class="tok-number">0x2160</span>...<span class="tok-number">0x2182</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L20"> <span class="tok-number">0x2185</span>...<span class="tok-number">0x2188</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L21"> <span class="tok-number">0x2189</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L22"> <span class="tok-number">0x2469</span>...<span class="tok-number">0x2473</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L23"> <span class="tok-number">0x247d</span>...<span class="tok-number">0x2487</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L24"> <span class="tok-number">0x2491</span>...<span class="tok-number">0x249b</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L25"> <span class="tok-number">0x24eb</span>...<span class="tok-number">0x24f4</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L26"> <span class="tok-number">0x24fe</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L27"> <span class="tok-number">0x277f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L28"> <span class="tok-number">0x2789</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L29"> <span class="tok-number">0x2793</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L30"> <span class="tok-number">0x2cfd</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L31"> <span class="tok-number">0x3007</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L32"> <span class="tok-number">0x3021</span>...<span class="tok-number">0x3029</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L33"> <span class="tok-number">0x3038</span>...<span class="tok-number">0x303a</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L34"> <span class="tok-number">0x3192</span>...<span class="tok-number">0x3195</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L35"> <span class="tok-number">0x3220</span>...<span class="tok-number">0x3229</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L36"> <span class="tok-number">0x3248</span>...<span class="tok-number">0x324f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L37"> <span class="tok-number">0x3251</span>...<span class="tok-number">0x325f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L38"> <span class="tok-number">0x3280</span>...<span class="tok-number">0x3289</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L39"> <span class="tok-number">0x32b1</span>...<span class="tok-number">0x32bf</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L40"> <span class="tok-number">0x3405</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L41"> <span class="tok-number">0x3483</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L42"> <span class="tok-number">0x382a</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L43"> <span class="tok-number">0x3b4d</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L44"> <span class="tok-number">0x4e00</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L45"> <span class="tok-number">0x4e03</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L46"> <span class="tok-number">0x4e07</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L47"> <span class="tok-number">0x4e09</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L48"> <span class="tok-number">0x4e5d</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L49"> <span class="tok-number">0x4e8c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L50"> <span class="tok-number">0x4e94</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L51"> <span class="tok-number">0x4e96</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L52"> <span class="tok-number">0x4ebf</span>...<span class="tok-number">0x4ec0</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L53"> <span class="tok-number">0x4edf</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L54"> <span class="tok-number">0x4ee8</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L55"> <span class="tok-number">0x4f0d</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L56"> <span class="tok-number">0x4f70</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L57"> <span class="tok-number">0x5104</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L58"> <span class="tok-number">0x5146</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L59"> <span class="tok-number">0x5169</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L60"> <span class="tok-number">0x516b</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L61"> <span class="tok-number">0x516d</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L62"> <span class="tok-number">0x5341</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L63"> <span class="tok-number">0x5343</span>...<span class="tok-number">0x5345</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L64"> <span class="tok-number">0x534c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L65"> <span class="tok-number">0x53c1</span>...<span class="tok-number">0x53c4</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L66"> <span class="tok-number">0x56db</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L67"> <span class="tok-number">0x58f1</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L68"> <span class="tok-number">0x58f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L69"> <span class="tok-number">0x5e7a</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L70"> <span class="tok-number">0x5efe</span>...<span class="tok-number">0x5eff</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L71"> <span class="tok-number">0x5f0c</span>...<span class="tok-number">0x5f0e</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L72"> <span class="tok-number">0x5f10</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L73"> <span class="tok-number">0x62fe</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L74"> <span class="tok-number">0x634c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L75"> <span class="tok-number">0x67d2</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L76"> <span class="tok-number">0x6f06</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L77"> <span class="tok-number">0x7396</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L78"> <span class="tok-number">0x767e</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L79"> <span class="tok-number">0x8086</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L80"> <span class="tok-number">0x842c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L81"> <span class="tok-number">0x8cae</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L82"> <span class="tok-number">0x8cb3</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L83"> <span class="tok-number">0x8d30</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L84"> <span class="tok-number">0x9621</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L85"> <span class="tok-number">0x9646</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L86"> <span class="tok-number">0x964c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L87"> <span class="tok-number">0x9678</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L88"> <span class="tok-number">0x96f6</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L89"> <span class="tok-number">0xa6e6</span>...<span class="tok-number">0xa6ef</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L90"> <span class="tok-number">0xa830</span>...<span class="tok-number">0xa835</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L91"> <span class="tok-number">0xf96b</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L92"> <span class="tok-number">0xf973</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L93"> <span class="tok-number">0xf978</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L94"> <span class="tok-number">0xf9b2</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L95"> <span class="tok-number">0xf9d1</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L96"> <span class="tok-number">0xf9d3</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L97"> <span class="tok-number">0xf9fd</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L98"> <span class="tok-number">0x10107</span>...<span class="tok-number">0x10133</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L99"> <span class="tok-number">0x10140</span>...<span class="tok-number">0x10174</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L100"> <span class="tok-number">0x10175</span>...<span class="tok-number">0x10178</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L101"> <span class="tok-number">0x1018a</span>...<span class="tok-number">0x1018b</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L102"> <span class="tok-number">0x102e1</span>...<span class="tok-number">0x102fb</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L103"> <span class="tok-number">0x10320</span>...<span class="tok-number">0x10323</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L104"> <span class="tok-number">0x10341</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L105"> <span class="tok-number">0x1034a</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L106"> <span class="tok-number">0x103d1</span>...<span class="tok-number">0x103d5</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L107"> <span class="tok-number">0x10858</span>...<span class="tok-number">0x1085f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L108"> <span class="tok-number">0x10879</span>...<span class="tok-number">0x1087f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L109"> <span class="tok-number">0x108a7</span>...<span class="tok-number">0x108af</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L110"> <span class="tok-number">0x108fb</span>...<span class="tok-number">0x108ff</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L111"> <span class="tok-number">0x10916</span>...<span class="tok-number">0x1091b</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L112"> <span class="tok-number">0x109bc</span>...<span class="tok-number">0x109bd</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L113"> <span class="tok-number">0x109c0</span>...<span class="tok-number">0x109cf</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L114"> <span class="tok-number">0x109d2</span>...<span class="tok-number">0x109ff</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L115"> <span class="tok-number">0x10a44</span>...<span class="tok-number">0x10a48</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L116"> <span class="tok-number">0x10a7d</span>...<span class="tok-number">0x10a7e</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L117"> <span class="tok-number">0x10a9d</span>...<span class="tok-number">0x10a9f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L118"> <span class="tok-number">0x10aeb</span>...<span class="tok-number">0x10aef</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L119"> <span class="tok-number">0x10b58</span>...<span class="tok-number">0x10b5f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L120"> <span class="tok-number">0x10b78</span>...<span class="tok-number">0x10b7f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L121"> <span class="tok-number">0x10ba9</span>...<span class="tok-number">0x10baf</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L122"> <span class="tok-number">0x10cfa</span>...<span class="tok-number">0x10cff</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L123"> <span class="tok-number">0x10e69</span>...<span class="tok-number">0x10e7e</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L124"> <span class="tok-number">0x10f1d</span>...<span class="tok-number">0x10f26</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L125"> <span class="tok-number">0x10f51</span>...<span class="tok-number">0x10f54</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L126"> <span class="tok-number">0x10fc5</span>...<span class="tok-number">0x10fcb</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L127"> <span class="tok-number">0x1105b</span>...<span class="tok-number">0x11065</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L128"> <span class="tok-number">0x111e1</span>...<span class="tok-number">0x111f4</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L129"> <span class="tok-number">0x1173a</span>...<span class="tok-number">0x1173b</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L130"> <span class="tok-number">0x118ea</span>...<span class="tok-number">0x118f2</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L131"> <span class="tok-number">0x11c5a</span>...<span class="tok-number">0x11c6c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L132"> <span class="tok-number">0x11fc0</span>...<span class="tok-number">0x11fd4</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L133"> <span class="tok-number">0x12400</span>...<span class="tok-number">0x1246e</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L134"> <span class="tok-number">0x16b5b</span>...<span class="tok-number">0x16b61</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L135"> <span class="tok-number">0x16e80</span>...<span class="tok-number">0x16e96</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L136"> <span class="tok-number">0x1d2c0</span>...<span class="tok-number">0x1d2d3</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L137"> <span class="tok-number">0x1d2e0</span>...<span class="tok-number">0x1d2f3</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L138"> <span class="tok-number">0x1d360</span>...<span class="tok-number">0x1d378</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L139"> <span class="tok-number">0x1e8c7</span>...<span class="tok-number">0x1e8cf</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L140"> <span class="tok-number">0x1ec71</span>...<span class="tok-number">0x1ecab</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L141"> <span class="tok-number">0x1ecad</span>...<span class="tok-number">0x1ecaf</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L142"> <span class="tok-number">0x1ecb1</span>...<span class="tok-number">0x1ecb4</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L143"> <span class="tok-number">0x1ed01</span>...<span class="tok-number">0x1ed2d</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L144"> <span class="tok-number">0x1ed2f</span>...<span class="tok-number">0x1ed3d</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L145"> <span class="tok-number">0x1f10b</span>...<span class="tok-number">0x1f10c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L146"> <span class="tok-number">0x20001</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L147"> <span class="tok-number">0x20064</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L148"> <span class="tok-number">0x200e2</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L149"> <span class="tok-number">0x20121</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L150"> <span class="tok-number">0x2092a</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L151"> <span class="tok-number">0x20983</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L152"> <span class="tok-number">0x2098c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L153"> <span class="tok-number">0x2099c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L154"> <span class="tok-number">0x20aea</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L155"> <span class="tok-number">0x20afd</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L156"> <span class="tok-number">0x20b19</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L157"> <span class="tok-number">0x22390</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L158"> <span class="tok-number">0x22998</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L159"> <span class="tok-number">0x23b1b</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L160"> <span class="tok-number">0x2626d</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L161"> <span class="tok-number">0x2f890</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L162"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">false</span>,</span>
<span class="line" id="L163"> };</span>
<span class="line" id="L164">}</span>
<span class="line" id="L165"></span>
<span class="line" id="L166"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L167"> <span class="tok-kw">if</span> (cp &lt; <span class="tok-number">0xb2</span> <span class="tok-kw">or</span> cp &gt; <span class="tok-number">0x1f10a</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L168"></span>
<span class="line" id="L169"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (cp) {</span>
<span class="line" id="L170"> <span class="tok-number">0xb2</span>...<span class="tok-number">0xb3</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L171"> <span class="tok-number">0xb9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L172"> <span class="tok-number">0x1369</span>...<span class="tok-number">0x1371</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L173"> <span class="tok-number">0x19da</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L174"> <span class="tok-number">0x2070</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L175"> <span class="tok-number">0x2074</span>...<span class="tok-number">0x2079</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L176"> <span class="tok-number">0x2080</span>...<span class="tok-number">0x2089</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L177"> <span class="tok-number">0x2460</span>...<span class="tok-number">0x2468</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L178"> <span class="tok-number">0x2474</span>...<span class="tok-number">0x247c</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L179"> <span class="tok-number">0x2488</span>...<span class="tok-number">0x2490</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L180"> <span class="tok-number">0x24ea</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L181"> <span class="tok-number">0x24f5</span>...<span class="tok-number">0x24fd</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L182"> <span class="tok-number">0x24ff</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L183"> <span class="tok-number">0x2776</span>...<span class="tok-number">0x277e</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L184"> <span class="tok-number">0x2780</span>...<span class="tok-number">0x2788</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L185"> <span class="tok-number">0x278a</span>...<span class="tok-number">0x2792</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L186"> <span class="tok-number">0x10a40</span>...<span class="tok-number">0x10a43</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L187"> <span class="tok-number">0x10e60</span>...<span class="tok-number">0x10e68</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L188"> <span class="tok-number">0x11052</span>...<span class="tok-number">0x1105a</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L189"> <span class="tok-number">0x1f100</span>...<span class="tok-number">0x1f10a</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L190"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">false</span>,</span>
<span class="line" id="L191"> };</span>
<span class="line" id="L192">}</span>
<span class="line" id="L193"></span>
<span class="line" id="L194"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isDecimal</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L195"> <span class="tok-kw">if</span> (cp &lt; <span class="tok-number">0x30</span> <span class="tok-kw">or</span> cp &gt; <span class="tok-number">0x1fbf9</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L196"></span>
<span class="line" id="L197"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (cp) {</span>
<span class="line" id="L198"> <span class="tok-number">0x30</span>...<span class="tok-number">0x39</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L199"> <span class="tok-number">0x660</span>...<span class="tok-number">0x669</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L200"> <span class="tok-number">0x6f0</span>...<span class="tok-number">0x6f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L201"> <span class="tok-number">0x7c0</span>...<span class="tok-number">0x7c9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L202"> <span class="tok-number">0x966</span>...<span class="tok-number">0x96f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L203"> <span class="tok-number">0x9e6</span>...<span class="tok-number">0x9ef</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L204"> <span class="tok-number">0xa66</span>...<span class="tok-number">0xa6f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L205"> <span class="tok-number">0xae6</span>...<span class="tok-number">0xaef</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L206"> <span class="tok-number">0xb66</span>...<span class="tok-number">0xb6f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L207"> <span class="tok-number">0xbe6</span>...<span class="tok-number">0xbef</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L208"> <span class="tok-number">0xc66</span>...<span class="tok-number">0xc6f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L209"> <span class="tok-number">0xce6</span>...<span class="tok-number">0xcef</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L210"> <span class="tok-number">0xd66</span>...<span class="tok-number">0xd6f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L211"> <span class="tok-number">0xde6</span>...<span class="tok-number">0xdef</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L212"> <span class="tok-number">0xe50</span>...<span class="tok-number">0xe59</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L213"> <span class="tok-number">0xed0</span>...<span class="tok-number">0xed9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L214"> <span class="tok-number">0xf20</span>...<span class="tok-number">0xf29</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L215"> <span class="tok-number">0x1040</span>...<span class="tok-number">0x1049</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L216"> <span class="tok-number">0x1090</span>...<span class="tok-number">0x1099</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L217"> <span class="tok-number">0x17e0</span>...<span class="tok-number">0x17e9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L218"> <span class="tok-number">0x1810</span>...<span class="tok-number">0x1819</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L219"> <span class="tok-number">0x1946</span>...<span class="tok-number">0x194f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L220"> <span class="tok-number">0x19d0</span>...<span class="tok-number">0x19d9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L221"> <span class="tok-number">0x1a80</span>...<span class="tok-number">0x1a89</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L222"> <span class="tok-number">0x1a90</span>...<span class="tok-number">0x1a99</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L223"> <span class="tok-number">0x1b50</span>...<span class="tok-number">0x1b59</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L224"> <span class="tok-number">0x1bb0</span>...<span class="tok-number">0x1bb9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L225"> <span class="tok-number">0x1c40</span>...<span class="tok-number">0x1c49</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L226"> <span class="tok-number">0x1c50</span>...<span class="tok-number">0x1c59</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L227"> <span class="tok-number">0xa620</span>...<span class="tok-number">0xa629</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L228"> <span class="tok-number">0xa8d0</span>...<span class="tok-number">0xa8d9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L229"> <span class="tok-number">0xa900</span>...<span class="tok-number">0xa909</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L230"> <span class="tok-number">0xa9d0</span>...<span class="tok-number">0xa9d9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L231"> <span class="tok-number">0xa9f0</span>...<span class="tok-number">0xa9f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L232"> <span class="tok-number">0xaa50</span>...<span class="tok-number">0xaa59</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L233"> <span class="tok-number">0xabf0</span>...<span class="tok-number">0xabf9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L234"> <span class="tok-number">0xff10</span>...<span class="tok-number">0xff19</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L235"> <span class="tok-number">0x104a0</span>...<span class="tok-number">0x104a9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L236"> <span class="tok-number">0x10d30</span>...<span class="tok-number">0x10d39</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L237"> <span class="tok-number">0x11066</span>...<span class="tok-number">0x1106f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L238"> <span class="tok-number">0x110f0</span>...<span class="tok-number">0x110f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L239"> <span class="tok-number">0x11136</span>...<span class="tok-number">0x1113f</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L240"> <span class="tok-number">0x111d0</span>...<span class="tok-number">0x111d9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L241"> <span class="tok-number">0x112f0</span>...<span class="tok-number">0x112f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L242"> <span class="tok-number">0x11450</span>...<span class="tok-number">0x11459</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L243"> <span class="tok-number">0x114d0</span>...<span class="tok-number">0x114d9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L244"> <span class="tok-number">0x11650</span>...<span class="tok-number">0x11659</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L245"> <span class="tok-number">0x116c0</span>...<span class="tok-number">0x116c9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L246"> <span class="tok-number">0x11730</span>...<span class="tok-number">0x11739</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L247"> <span class="tok-number">0x118e0</span>...<span class="tok-number">0x118e9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L248"> <span class="tok-number">0x11950</span>...<span class="tok-number">0x11959</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L249"> <span class="tok-number">0x11c50</span>...<span class="tok-number">0x11c59</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L250"> <span class="tok-number">0x11d50</span>...<span class="tok-number">0x11d59</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L251"> <span class="tok-number">0x11da0</span>...<span class="tok-number">0x11da9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L252"> <span class="tok-number">0x11f50</span>...<span class="tok-number">0x11f59</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L253"> <span class="tok-number">0x16a60</span>...<span class="tok-number">0x16a69</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L254"> <span class="tok-number">0x16ac0</span>...<span class="tok-number">0x16ac9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L255"> <span class="tok-number">0x16b50</span>...<span class="tok-number">0x16b59</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L256"> <span class="tok-number">0x1d7ce</span>...<span class="tok-number">0x1d7ff</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L257"> <span class="tok-number">0x1e140</span>...<span class="tok-number">0x1e149</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L258"> <span class="tok-number">0x1e2f0</span>...<span class="tok-number">0x1e2f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L259"> <span class="tok-number">0x1e4f0</span>...<span class="tok-number">0x1e4f9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L260"> <span class="tok-number">0x1e950</span>...<span class="tok-number">0x1e959</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L261"> <span class="tok-number">0x1fbf0</span>...<span class="tok-number">0x1fbf9</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L262"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">false</span>,</span>
<span class="line" id="L263"> };</span>
<span class="line" id="L264">}</span>
<span class="line" id="L265"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,938 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>autogen/hangul_syllable_type.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">// Autogenerated from https://www.unicode.org/Public/15.0.0/ucd/</span>
</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Kind = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L4"> L,</span>
<span class="line" id="L5"> LV,</span>
<span class="line" id="L6"> LVT,</span>
<span class="line" id="L7"> T,</span>
<span class="line" id="L8"> V,</span>
<span class="line" id="L9">};</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-comment">/// `syllableType` maps the code point to its Hangul Syllable Type.</span></span>
<span class="line" id="L12"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">syllableType</span>(cp: <span class="tok-type">u21</span>) ?Kind {</span>
<span class="line" id="L13"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (cp) {</span>
<span class="line" id="L14"> <span class="tok-number">0x1100</span>...<span class="tok-number">0x115F</span> =&gt; .L,</span>
<span class="line" id="L15"> <span class="tok-number">0xA960</span>...<span class="tok-number">0xA97C</span> =&gt; .L,</span>
<span class="line" id="L16"> <span class="tok-number">0x1160</span>...<span class="tok-number">0x11A7</span> =&gt; .V,</span>
<span class="line" id="L17"> <span class="tok-number">0xD7B0</span>...<span class="tok-number">0xD7C6</span> =&gt; .V,</span>
<span class="line" id="L18"> <span class="tok-number">0x11A8</span>...<span class="tok-number">0x11FF</span> =&gt; .T,</span>
<span class="line" id="L19"> <span class="tok-number">0xD7CB</span>...<span class="tok-number">0xD7FB</span> =&gt; .T,</span>
<span class="line" id="L20"> <span class="tok-number">0xAC00</span> =&gt; .LV,</span>
<span class="line" id="L21"> <span class="tok-number">0xAC1C</span> =&gt; .LV,</span>
<span class="line" id="L22"> <span class="tok-number">0xAC38</span> =&gt; .LV,</span>
<span class="line" id="L23"> <span class="tok-number">0xAC54</span> =&gt; .LV,</span>
<span class="line" id="L24"> <span class="tok-number">0xAC70</span> =&gt; .LV,</span>
<span class="line" id="L25"> <span class="tok-number">0xAC8C</span> =&gt; .LV,</span>
<span class="line" id="L26"> <span class="tok-number">0xACA8</span> =&gt; .LV,</span>
<span class="line" id="L27"> <span class="tok-number">0xACC4</span> =&gt; .LV,</span>
<span class="line" id="L28"> <span class="tok-number">0xACE0</span> =&gt; .LV,</span>
<span class="line" id="L29"> <span class="tok-number">0xACFC</span> =&gt; .LV,</span>
<span class="line" id="L30"> <span class="tok-number">0xAD18</span> =&gt; .LV,</span>
<span class="line" id="L31"> <span class="tok-number">0xAD34</span> =&gt; .LV,</span>
<span class="line" id="L32"> <span class="tok-number">0xAD50</span> =&gt; .LV,</span>
<span class="line" id="L33"> <span class="tok-number">0xAD6C</span> =&gt; .LV,</span>
<span class="line" id="L34"> <span class="tok-number">0xAD88</span> =&gt; .LV,</span>
<span class="line" id="L35"> <span class="tok-number">0xADA4</span> =&gt; .LV,</span>
<span class="line" id="L36"> <span class="tok-number">0xADC0</span> =&gt; .LV,</span>
<span class="line" id="L37"> <span class="tok-number">0xADDC</span> =&gt; .LV,</span>
<span class="line" id="L38"> <span class="tok-number">0xADF8</span> =&gt; .LV,</span>
<span class="line" id="L39"> <span class="tok-number">0xAE14</span> =&gt; .LV,</span>
<span class="line" id="L40"> <span class="tok-number">0xAE30</span> =&gt; .LV,</span>
<span class="line" id="L41"> <span class="tok-number">0xAE4C</span> =&gt; .LV,</span>
<span class="line" id="L42"> <span class="tok-number">0xAE68</span> =&gt; .LV,</span>
<span class="line" id="L43"> <span class="tok-number">0xAE84</span> =&gt; .LV,</span>
<span class="line" id="L44"> <span class="tok-number">0xAEA0</span> =&gt; .LV,</span>
<span class="line" id="L45"> <span class="tok-number">0xAEBC</span> =&gt; .LV,</span>
<span class="line" id="L46"> <span class="tok-number">0xAED8</span> =&gt; .LV,</span>
<span class="line" id="L47"> <span class="tok-number">0xAEF4</span> =&gt; .LV,</span>
<span class="line" id="L48"> <span class="tok-number">0xAF10</span> =&gt; .LV,</span>
<span class="line" id="L49"> <span class="tok-number">0xAF2C</span> =&gt; .LV,</span>
<span class="line" id="L50"> <span class="tok-number">0xAF48</span> =&gt; .LV,</span>
<span class="line" id="L51"> <span class="tok-number">0xAF64</span> =&gt; .LV,</span>
<span class="line" id="L52"> <span class="tok-number">0xAF80</span> =&gt; .LV,</span>
<span class="line" id="L53"> <span class="tok-number">0xAF9C</span> =&gt; .LV,</span>
<span class="line" id="L54"> <span class="tok-number">0xAFB8</span> =&gt; .LV,</span>
<span class="line" id="L55"> <span class="tok-number">0xAFD4</span> =&gt; .LV,</span>
<span class="line" id="L56"> <span class="tok-number">0xAFF0</span> =&gt; .LV,</span>
<span class="line" id="L57"> <span class="tok-number">0xB00C</span> =&gt; .LV,</span>
<span class="line" id="L58"> <span class="tok-number">0xB028</span> =&gt; .LV,</span>
<span class="line" id="L59"> <span class="tok-number">0xB044</span> =&gt; .LV,</span>
<span class="line" id="L60"> <span class="tok-number">0xB060</span> =&gt; .LV,</span>
<span class="line" id="L61"> <span class="tok-number">0xB07C</span> =&gt; .LV,</span>
<span class="line" id="L62"> <span class="tok-number">0xB098</span> =&gt; .LV,</span>
<span class="line" id="L63"> <span class="tok-number">0xB0B4</span> =&gt; .LV,</span>
<span class="line" id="L64"> <span class="tok-number">0xB0D0</span> =&gt; .LV,</span>
<span class="line" id="L65"> <span class="tok-number">0xB0EC</span> =&gt; .LV,</span>
<span class="line" id="L66"> <span class="tok-number">0xB108</span> =&gt; .LV,</span>
<span class="line" id="L67"> <span class="tok-number">0xB124</span> =&gt; .LV,</span>
<span class="line" id="L68"> <span class="tok-number">0xB140</span> =&gt; .LV,</span>
<span class="line" id="L69"> <span class="tok-number">0xB15C</span> =&gt; .LV,</span>
<span class="line" id="L70"> <span class="tok-number">0xB178</span> =&gt; .LV,</span>
<span class="line" id="L71"> <span class="tok-number">0xB194</span> =&gt; .LV,</span>
<span class="line" id="L72"> <span class="tok-number">0xB1B0</span> =&gt; .LV,</span>
<span class="line" id="L73"> <span class="tok-number">0xB1CC</span> =&gt; .LV,</span>
<span class="line" id="L74"> <span class="tok-number">0xB1E8</span> =&gt; .LV,</span>
<span class="line" id="L75"> <span class="tok-number">0xB204</span> =&gt; .LV,</span>
<span class="line" id="L76"> <span class="tok-number">0xB220</span> =&gt; .LV,</span>
<span class="line" id="L77"> <span class="tok-number">0xB23C</span> =&gt; .LV,</span>
<span class="line" id="L78"> <span class="tok-number">0xB258</span> =&gt; .LV,</span>
<span class="line" id="L79"> <span class="tok-number">0xB274</span> =&gt; .LV,</span>
<span class="line" id="L80"> <span class="tok-number">0xB290</span> =&gt; .LV,</span>
<span class="line" id="L81"> <span class="tok-number">0xB2AC</span> =&gt; .LV,</span>
<span class="line" id="L82"> <span class="tok-number">0xB2C8</span> =&gt; .LV,</span>
<span class="line" id="L83"> <span class="tok-number">0xB2E4</span> =&gt; .LV,</span>
<span class="line" id="L84"> <span class="tok-number">0xB300</span> =&gt; .LV,</span>
<span class="line" id="L85"> <span class="tok-number">0xB31C</span> =&gt; .LV,</span>
<span class="line" id="L86"> <span class="tok-number">0xB338</span> =&gt; .LV,</span>
<span class="line" id="L87"> <span class="tok-number">0xB354</span> =&gt; .LV,</span>
<span class="line" id="L88"> <span class="tok-number">0xB370</span> =&gt; .LV,</span>
<span class="line" id="L89"> <span class="tok-number">0xB38C</span> =&gt; .LV,</span>
<span class="line" id="L90"> <span class="tok-number">0xB3A8</span> =&gt; .LV,</span>
<span class="line" id="L91"> <span class="tok-number">0xB3C4</span> =&gt; .LV,</span>
<span class="line" id="L92"> <span class="tok-number">0xB3E0</span> =&gt; .LV,</span>
<span class="line" id="L93"> <span class="tok-number">0xB3FC</span> =&gt; .LV,</span>
<span class="line" id="L94"> <span class="tok-number">0xB418</span> =&gt; .LV,</span>
<span class="line" id="L95"> <span class="tok-number">0xB434</span> =&gt; .LV,</span>
<span class="line" id="L96"> <span class="tok-number">0xB450</span> =&gt; .LV,</span>
<span class="line" id="L97"> <span class="tok-number">0xB46C</span> =&gt; .LV,</span>
<span class="line" id="L98"> <span class="tok-number">0xB488</span> =&gt; .LV,</span>
<span class="line" id="L99"> <span class="tok-number">0xB4A4</span> =&gt; .LV,</span>
<span class="line" id="L100"> <span class="tok-number">0xB4C0</span> =&gt; .LV,</span>
<span class="line" id="L101"> <span class="tok-number">0xB4DC</span> =&gt; .LV,</span>
<span class="line" id="L102"> <span class="tok-number">0xB4F8</span> =&gt; .LV,</span>
<span class="line" id="L103"> <span class="tok-number">0xB514</span> =&gt; .LV,</span>
<span class="line" id="L104"> <span class="tok-number">0xB530</span> =&gt; .LV,</span>
<span class="line" id="L105"> <span class="tok-number">0xB54C</span> =&gt; .LV,</span>
<span class="line" id="L106"> <span class="tok-number">0xB568</span> =&gt; .LV,</span>
<span class="line" id="L107"> <span class="tok-number">0xB584</span> =&gt; .LV,</span>
<span class="line" id="L108"> <span class="tok-number">0xB5A0</span> =&gt; .LV,</span>
<span class="line" id="L109"> <span class="tok-number">0xB5BC</span> =&gt; .LV,</span>
<span class="line" id="L110"> <span class="tok-number">0xB5D8</span> =&gt; .LV,</span>
<span class="line" id="L111"> <span class="tok-number">0xB5F4</span> =&gt; .LV,</span>
<span class="line" id="L112"> <span class="tok-number">0xB610</span> =&gt; .LV,</span>
<span class="line" id="L113"> <span class="tok-number">0xB62C</span> =&gt; .LV,</span>
<span class="line" id="L114"> <span class="tok-number">0xB648</span> =&gt; .LV,</span>
<span class="line" id="L115"> <span class="tok-number">0xB664</span> =&gt; .LV,</span>
<span class="line" id="L116"> <span class="tok-number">0xB680</span> =&gt; .LV,</span>
<span class="line" id="L117"> <span class="tok-number">0xB69C</span> =&gt; .LV,</span>
<span class="line" id="L118"> <span class="tok-number">0xB6B8</span> =&gt; .LV,</span>
<span class="line" id="L119"> <span class="tok-number">0xB6D4</span> =&gt; .LV,</span>
<span class="line" id="L120"> <span class="tok-number">0xB6F0</span> =&gt; .LV,</span>
<span class="line" id="L121"> <span class="tok-number">0xB70C</span> =&gt; .LV,</span>
<span class="line" id="L122"> <span class="tok-number">0xB728</span> =&gt; .LV,</span>
<span class="line" id="L123"> <span class="tok-number">0xB744</span> =&gt; .LV,</span>
<span class="line" id="L124"> <span class="tok-number">0xB760</span> =&gt; .LV,</span>
<span class="line" id="L125"> <span class="tok-number">0xB77C</span> =&gt; .LV,</span>
<span class="line" id="L126"> <span class="tok-number">0xB798</span> =&gt; .LV,</span>
<span class="line" id="L127"> <span class="tok-number">0xB7B4</span> =&gt; .LV,</span>
<span class="line" id="L128"> <span class="tok-number">0xB7D0</span> =&gt; .LV,</span>
<span class="line" id="L129"> <span class="tok-number">0xB7EC</span> =&gt; .LV,</span>
<span class="line" id="L130"> <span class="tok-number">0xB808</span> =&gt; .LV,</span>
<span class="line" id="L131"> <span class="tok-number">0xB824</span> =&gt; .LV,</span>
<span class="line" id="L132"> <span class="tok-number">0xB840</span> =&gt; .LV,</span>
<span class="line" id="L133"> <span class="tok-number">0xB85C</span> =&gt; .LV,</span>
<span class="line" id="L134"> <span class="tok-number">0xB878</span> =&gt; .LV,</span>
<span class="line" id="L135"> <span class="tok-number">0xB894</span> =&gt; .LV,</span>
<span class="line" id="L136"> <span class="tok-number">0xB8B0</span> =&gt; .LV,</span>
<span class="line" id="L137"> <span class="tok-number">0xB8CC</span> =&gt; .LV,</span>
<span class="line" id="L138"> <span class="tok-number">0xB8E8</span> =&gt; .LV,</span>
<span class="line" id="L139"> <span class="tok-number">0xB904</span> =&gt; .LV,</span>
<span class="line" id="L140"> <span class="tok-number">0xB920</span> =&gt; .LV,</span>
<span class="line" id="L141"> <span class="tok-number">0xB93C</span> =&gt; .LV,</span>
<span class="line" id="L142"> <span class="tok-number">0xB958</span> =&gt; .LV,</span>
<span class="line" id="L143"> <span class="tok-number">0xB974</span> =&gt; .LV,</span>
<span class="line" id="L144"> <span class="tok-number">0xB990</span> =&gt; .LV,</span>
<span class="line" id="L145"> <span class="tok-number">0xB9AC</span> =&gt; .LV,</span>
<span class="line" id="L146"> <span class="tok-number">0xB9C8</span> =&gt; .LV,</span>
<span class="line" id="L147"> <span class="tok-number">0xB9E4</span> =&gt; .LV,</span>
<span class="line" id="L148"> <span class="tok-number">0xBA00</span> =&gt; .LV,</span>
<span class="line" id="L149"> <span class="tok-number">0xBA1C</span> =&gt; .LV,</span>
<span class="line" id="L150"> <span class="tok-number">0xBA38</span> =&gt; .LV,</span>
<span class="line" id="L151"> <span class="tok-number">0xBA54</span> =&gt; .LV,</span>
<span class="line" id="L152"> <span class="tok-number">0xBA70</span> =&gt; .LV,</span>
<span class="line" id="L153"> <span class="tok-number">0xBA8C</span> =&gt; .LV,</span>
<span class="line" id="L154"> <span class="tok-number">0xBAA8</span> =&gt; .LV,</span>
<span class="line" id="L155"> <span class="tok-number">0xBAC4</span> =&gt; .LV,</span>
<span class="line" id="L156"> <span class="tok-number">0xBAE0</span> =&gt; .LV,</span>
<span class="line" id="L157"> <span class="tok-number">0xBAFC</span> =&gt; .LV,</span>
<span class="line" id="L158"> <span class="tok-number">0xBB18</span> =&gt; .LV,</span>
<span class="line" id="L159"> <span class="tok-number">0xBB34</span> =&gt; .LV,</span>
<span class="line" id="L160"> <span class="tok-number">0xBB50</span> =&gt; .LV,</span>
<span class="line" id="L161"> <span class="tok-number">0xBB6C</span> =&gt; .LV,</span>
<span class="line" id="L162"> <span class="tok-number">0xBB88</span> =&gt; .LV,</span>
<span class="line" id="L163"> <span class="tok-number">0xBBA4</span> =&gt; .LV,</span>
<span class="line" id="L164"> <span class="tok-number">0xBBC0</span> =&gt; .LV,</span>
<span class="line" id="L165"> <span class="tok-number">0xBBDC</span> =&gt; .LV,</span>
<span class="line" id="L166"> <span class="tok-number">0xBBF8</span> =&gt; .LV,</span>
<span class="line" id="L167"> <span class="tok-number">0xBC14</span> =&gt; .LV,</span>
<span class="line" id="L168"> <span class="tok-number">0xBC30</span> =&gt; .LV,</span>
<span class="line" id="L169"> <span class="tok-number">0xBC4C</span> =&gt; .LV,</span>
<span class="line" id="L170"> <span class="tok-number">0xBC68</span> =&gt; .LV,</span>
<span class="line" id="L171"> <span class="tok-number">0xBC84</span> =&gt; .LV,</span>
<span class="line" id="L172"> <span class="tok-number">0xBCA0</span> =&gt; .LV,</span>
<span class="line" id="L173"> <span class="tok-number">0xBCBC</span> =&gt; .LV,</span>
<span class="line" id="L174"> <span class="tok-number">0xBCD8</span> =&gt; .LV,</span>
<span class="line" id="L175"> <span class="tok-number">0xBCF4</span> =&gt; .LV,</span>
<span class="line" id="L176"> <span class="tok-number">0xBD10</span> =&gt; .LV,</span>
<span class="line" id="L177"> <span class="tok-number">0xBD2C</span> =&gt; .LV,</span>
<span class="line" id="L178"> <span class="tok-number">0xBD48</span> =&gt; .LV,</span>
<span class="line" id="L179"> <span class="tok-number">0xBD64</span> =&gt; .LV,</span>
<span class="line" id="L180"> <span class="tok-number">0xBD80</span> =&gt; .LV,</span>
<span class="line" id="L181"> <span class="tok-number">0xBD9C</span> =&gt; .LV,</span>
<span class="line" id="L182"> <span class="tok-number">0xBDB8</span> =&gt; .LV,</span>
<span class="line" id="L183"> <span class="tok-number">0xBDD4</span> =&gt; .LV,</span>
<span class="line" id="L184"> <span class="tok-number">0xBDF0</span> =&gt; .LV,</span>
<span class="line" id="L185"> <span class="tok-number">0xBE0C</span> =&gt; .LV,</span>
<span class="line" id="L186"> <span class="tok-number">0xBE28</span> =&gt; .LV,</span>
<span class="line" id="L187"> <span class="tok-number">0xBE44</span> =&gt; .LV,</span>
<span class="line" id="L188"> <span class="tok-number">0xBE60</span> =&gt; .LV,</span>
<span class="line" id="L189"> <span class="tok-number">0xBE7C</span> =&gt; .LV,</span>
<span class="line" id="L190"> <span class="tok-number">0xBE98</span> =&gt; .LV,</span>
<span class="line" id="L191"> <span class="tok-number">0xBEB4</span> =&gt; .LV,</span>
<span class="line" id="L192"> <span class="tok-number">0xBED0</span> =&gt; .LV,</span>
<span class="line" id="L193"> <span class="tok-number">0xBEEC</span> =&gt; .LV,</span>
<span class="line" id="L194"> <span class="tok-number">0xBF08</span> =&gt; .LV,</span>
<span class="line" id="L195"> <span class="tok-number">0xBF24</span> =&gt; .LV,</span>
<span class="line" id="L196"> <span class="tok-number">0xBF40</span> =&gt; .LV,</span>
<span class="line" id="L197"> <span class="tok-number">0xBF5C</span> =&gt; .LV,</span>
<span class="line" id="L198"> <span class="tok-number">0xBF78</span> =&gt; .LV,</span>
<span class="line" id="L199"> <span class="tok-number">0xBF94</span> =&gt; .LV,</span>
<span class="line" id="L200"> <span class="tok-number">0xBFB0</span> =&gt; .LV,</span>
<span class="line" id="L201"> <span class="tok-number">0xBFCC</span> =&gt; .LV,</span>
<span class="line" id="L202"> <span class="tok-number">0xBFE8</span> =&gt; .LV,</span>
<span class="line" id="L203"> <span class="tok-number">0xC004</span> =&gt; .LV,</span>
<span class="line" id="L204"> <span class="tok-number">0xC020</span> =&gt; .LV,</span>
<span class="line" id="L205"> <span class="tok-number">0xC03C</span> =&gt; .LV,</span>
<span class="line" id="L206"> <span class="tok-number">0xC058</span> =&gt; .LV,</span>
<span class="line" id="L207"> <span class="tok-number">0xC074</span> =&gt; .LV,</span>
<span class="line" id="L208"> <span class="tok-number">0xC090</span> =&gt; .LV,</span>
<span class="line" id="L209"> <span class="tok-number">0xC0AC</span> =&gt; .LV,</span>
<span class="line" id="L210"> <span class="tok-number">0xC0C8</span> =&gt; .LV,</span>
<span class="line" id="L211"> <span class="tok-number">0xC0E4</span> =&gt; .LV,</span>
<span class="line" id="L212"> <span class="tok-number">0xC100</span> =&gt; .LV,</span>
<span class="line" id="L213"> <span class="tok-number">0xC11C</span> =&gt; .LV,</span>
<span class="line" id="L214"> <span class="tok-number">0xC138</span> =&gt; .LV,</span>
<span class="line" id="L215"> <span class="tok-number">0xC154</span> =&gt; .LV,</span>
<span class="line" id="L216"> <span class="tok-number">0xC170</span> =&gt; .LV,</span>
<span class="line" id="L217"> <span class="tok-number">0xC18C</span> =&gt; .LV,</span>
<span class="line" id="L218"> <span class="tok-number">0xC1A8</span> =&gt; .LV,</span>
<span class="line" id="L219"> <span class="tok-number">0xC1C4</span> =&gt; .LV,</span>
<span class="line" id="L220"> <span class="tok-number">0xC1E0</span> =&gt; .LV,</span>
<span class="line" id="L221"> <span class="tok-number">0xC1FC</span> =&gt; .LV,</span>
<span class="line" id="L222"> <span class="tok-number">0xC218</span> =&gt; .LV,</span>
<span class="line" id="L223"> <span class="tok-number">0xC234</span> =&gt; .LV,</span>
<span class="line" id="L224"> <span class="tok-number">0xC250</span> =&gt; .LV,</span>
<span class="line" id="L225"> <span class="tok-number">0xC26C</span> =&gt; .LV,</span>
<span class="line" id="L226"> <span class="tok-number">0xC288</span> =&gt; .LV,</span>
<span class="line" id="L227"> <span class="tok-number">0xC2A4</span> =&gt; .LV,</span>
<span class="line" id="L228"> <span class="tok-number">0xC2C0</span> =&gt; .LV,</span>
<span class="line" id="L229"> <span class="tok-number">0xC2DC</span> =&gt; .LV,</span>
<span class="line" id="L230"> <span class="tok-number">0xC2F8</span> =&gt; .LV,</span>
<span class="line" id="L231"> <span class="tok-number">0xC314</span> =&gt; .LV,</span>
<span class="line" id="L232"> <span class="tok-number">0xC330</span> =&gt; .LV,</span>
<span class="line" id="L233"> <span class="tok-number">0xC34C</span> =&gt; .LV,</span>
<span class="line" id="L234"> <span class="tok-number">0xC368</span> =&gt; .LV,</span>
<span class="line" id="L235"> <span class="tok-number">0xC384</span> =&gt; .LV,</span>
<span class="line" id="L236"> <span class="tok-number">0xC3A0</span> =&gt; .LV,</span>
<span class="line" id="L237"> <span class="tok-number">0xC3BC</span> =&gt; .LV,</span>
<span class="line" id="L238"> <span class="tok-number">0xC3D8</span> =&gt; .LV,</span>
<span class="line" id="L239"> <span class="tok-number">0xC3F4</span> =&gt; .LV,</span>
<span class="line" id="L240"> <span class="tok-number">0xC410</span> =&gt; .LV,</span>
<span class="line" id="L241"> <span class="tok-number">0xC42C</span> =&gt; .LV,</span>
<span class="line" id="L242"> <span class="tok-number">0xC448</span> =&gt; .LV,</span>
<span class="line" id="L243"> <span class="tok-number">0xC464</span> =&gt; .LV,</span>
<span class="line" id="L244"> <span class="tok-number">0xC480</span> =&gt; .LV,</span>
<span class="line" id="L245"> <span class="tok-number">0xC49C</span> =&gt; .LV,</span>
<span class="line" id="L246"> <span class="tok-number">0xC4B8</span> =&gt; .LV,</span>
<span class="line" id="L247"> <span class="tok-number">0xC4D4</span> =&gt; .LV,</span>
<span class="line" id="L248"> <span class="tok-number">0xC4F0</span> =&gt; .LV,</span>
<span class="line" id="L249"> <span class="tok-number">0xC50C</span> =&gt; .LV,</span>
<span class="line" id="L250"> <span class="tok-number">0xC528</span> =&gt; .LV,</span>
<span class="line" id="L251"> <span class="tok-number">0xC544</span> =&gt; .LV,</span>
<span class="line" id="L252"> <span class="tok-number">0xC560</span> =&gt; .LV,</span>
<span class="line" id="L253"> <span class="tok-number">0xC57C</span> =&gt; .LV,</span>
<span class="line" id="L254"> <span class="tok-number">0xC598</span> =&gt; .LV,</span>
<span class="line" id="L255"> <span class="tok-number">0xC5B4</span> =&gt; .LV,</span>
<span class="line" id="L256"> <span class="tok-number">0xC5D0</span> =&gt; .LV,</span>
<span class="line" id="L257"> <span class="tok-number">0xC5EC</span> =&gt; .LV,</span>
<span class="line" id="L258"> <span class="tok-number">0xC608</span> =&gt; .LV,</span>
<span class="line" id="L259"> <span class="tok-number">0xC624</span> =&gt; .LV,</span>
<span class="line" id="L260"> <span class="tok-number">0xC640</span> =&gt; .LV,</span>
<span class="line" id="L261"> <span class="tok-number">0xC65C</span> =&gt; .LV,</span>
<span class="line" id="L262"> <span class="tok-number">0xC678</span> =&gt; .LV,</span>
<span class="line" id="L263"> <span class="tok-number">0xC694</span> =&gt; .LV,</span>
<span class="line" id="L264"> <span class="tok-number">0xC6B0</span> =&gt; .LV,</span>
<span class="line" id="L265"> <span class="tok-number">0xC6CC</span> =&gt; .LV,</span>
<span class="line" id="L266"> <span class="tok-number">0xC6E8</span> =&gt; .LV,</span>
<span class="line" id="L267"> <span class="tok-number">0xC704</span> =&gt; .LV,</span>
<span class="line" id="L268"> <span class="tok-number">0xC720</span> =&gt; .LV,</span>
<span class="line" id="L269"> <span class="tok-number">0xC73C</span> =&gt; .LV,</span>
<span class="line" id="L270"> <span class="tok-number">0xC758</span> =&gt; .LV,</span>
<span class="line" id="L271"> <span class="tok-number">0xC774</span> =&gt; .LV,</span>
<span class="line" id="L272"> <span class="tok-number">0xC790</span> =&gt; .LV,</span>
<span class="line" id="L273"> <span class="tok-number">0xC7AC</span> =&gt; .LV,</span>
<span class="line" id="L274"> <span class="tok-number">0xC7C8</span> =&gt; .LV,</span>
<span class="line" id="L275"> <span class="tok-number">0xC7E4</span> =&gt; .LV,</span>
<span class="line" id="L276"> <span class="tok-number">0xC800</span> =&gt; .LV,</span>
<span class="line" id="L277"> <span class="tok-number">0xC81C</span> =&gt; .LV,</span>
<span class="line" id="L278"> <span class="tok-number">0xC838</span> =&gt; .LV,</span>
<span class="line" id="L279"> <span class="tok-number">0xC854</span> =&gt; .LV,</span>
<span class="line" id="L280"> <span class="tok-number">0xC870</span> =&gt; .LV,</span>
<span class="line" id="L281"> <span class="tok-number">0xC88C</span> =&gt; .LV,</span>
<span class="line" id="L282"> <span class="tok-number">0xC8A8</span> =&gt; .LV,</span>
<span class="line" id="L283"> <span class="tok-number">0xC8C4</span> =&gt; .LV,</span>
<span class="line" id="L284"> <span class="tok-number">0xC8E0</span> =&gt; .LV,</span>
<span class="line" id="L285"> <span class="tok-number">0xC8FC</span> =&gt; .LV,</span>
<span class="line" id="L286"> <span class="tok-number">0xC918</span> =&gt; .LV,</span>
<span class="line" id="L287"> <span class="tok-number">0xC934</span> =&gt; .LV,</span>
<span class="line" id="L288"> <span class="tok-number">0xC950</span> =&gt; .LV,</span>
<span class="line" id="L289"> <span class="tok-number">0xC96C</span> =&gt; .LV,</span>
<span class="line" id="L290"> <span class="tok-number">0xC988</span> =&gt; .LV,</span>
<span class="line" id="L291"> <span class="tok-number">0xC9A4</span> =&gt; .LV,</span>
<span class="line" id="L292"> <span class="tok-number">0xC9C0</span> =&gt; .LV,</span>
<span class="line" id="L293"> <span class="tok-number">0xC9DC</span> =&gt; .LV,</span>
<span class="line" id="L294"> <span class="tok-number">0xC9F8</span> =&gt; .LV,</span>
<span class="line" id="L295"> <span class="tok-number">0xCA14</span> =&gt; .LV,</span>
<span class="line" id="L296"> <span class="tok-number">0xCA30</span> =&gt; .LV,</span>
<span class="line" id="L297"> <span class="tok-number">0xCA4C</span> =&gt; .LV,</span>
<span class="line" id="L298"> <span class="tok-number">0xCA68</span> =&gt; .LV,</span>
<span class="line" id="L299"> <span class="tok-number">0xCA84</span> =&gt; .LV,</span>
<span class="line" id="L300"> <span class="tok-number">0xCAA0</span> =&gt; .LV,</span>
<span class="line" id="L301"> <span class="tok-number">0xCABC</span> =&gt; .LV,</span>
<span class="line" id="L302"> <span class="tok-number">0xCAD8</span> =&gt; .LV,</span>
<span class="line" id="L303"> <span class="tok-number">0xCAF4</span> =&gt; .LV,</span>
<span class="line" id="L304"> <span class="tok-number">0xCB10</span> =&gt; .LV,</span>
<span class="line" id="L305"> <span class="tok-number">0xCB2C</span> =&gt; .LV,</span>
<span class="line" id="L306"> <span class="tok-number">0xCB48</span> =&gt; .LV,</span>
<span class="line" id="L307"> <span class="tok-number">0xCB64</span> =&gt; .LV,</span>
<span class="line" id="L308"> <span class="tok-number">0xCB80</span> =&gt; .LV,</span>
<span class="line" id="L309"> <span class="tok-number">0xCB9C</span> =&gt; .LV,</span>
<span class="line" id="L310"> <span class="tok-number">0xCBB8</span> =&gt; .LV,</span>
<span class="line" id="L311"> <span class="tok-number">0xCBD4</span> =&gt; .LV,</span>
<span class="line" id="L312"> <span class="tok-number">0xCBF0</span> =&gt; .LV,</span>
<span class="line" id="L313"> <span class="tok-number">0xCC0C</span> =&gt; .LV,</span>
<span class="line" id="L314"> <span class="tok-number">0xCC28</span> =&gt; .LV,</span>
<span class="line" id="L315"> <span class="tok-number">0xCC44</span> =&gt; .LV,</span>
<span class="line" id="L316"> <span class="tok-number">0xCC60</span> =&gt; .LV,</span>
<span class="line" id="L317"> <span class="tok-number">0xCC7C</span> =&gt; .LV,</span>
<span class="line" id="L318"> <span class="tok-number">0xCC98</span> =&gt; .LV,</span>
<span class="line" id="L319"> <span class="tok-number">0xCCB4</span> =&gt; .LV,</span>
<span class="line" id="L320"> <span class="tok-number">0xCCD0</span> =&gt; .LV,</span>
<span class="line" id="L321"> <span class="tok-number">0xCCEC</span> =&gt; .LV,</span>
<span class="line" id="L322"> <span class="tok-number">0xCD08</span> =&gt; .LV,</span>
<span class="line" id="L323"> <span class="tok-number">0xCD24</span> =&gt; .LV,</span>
<span class="line" id="L324"> <span class="tok-number">0xCD40</span> =&gt; .LV,</span>
<span class="line" id="L325"> <span class="tok-number">0xCD5C</span> =&gt; .LV,</span>
<span class="line" id="L326"> <span class="tok-number">0xCD78</span> =&gt; .LV,</span>
<span class="line" id="L327"> <span class="tok-number">0xCD94</span> =&gt; .LV,</span>
<span class="line" id="L328"> <span class="tok-number">0xCDB0</span> =&gt; .LV,</span>
<span class="line" id="L329"> <span class="tok-number">0xCDCC</span> =&gt; .LV,</span>
<span class="line" id="L330"> <span class="tok-number">0xCDE8</span> =&gt; .LV,</span>
<span class="line" id="L331"> <span class="tok-number">0xCE04</span> =&gt; .LV,</span>
<span class="line" id="L332"> <span class="tok-number">0xCE20</span> =&gt; .LV,</span>
<span class="line" id="L333"> <span class="tok-number">0xCE3C</span> =&gt; .LV,</span>
<span class="line" id="L334"> <span class="tok-number">0xCE58</span> =&gt; .LV,</span>
<span class="line" id="L335"> <span class="tok-number">0xCE74</span> =&gt; .LV,</span>
<span class="line" id="L336"> <span class="tok-number">0xCE90</span> =&gt; .LV,</span>
<span class="line" id="L337"> <span class="tok-number">0xCEAC</span> =&gt; .LV,</span>
<span class="line" id="L338"> <span class="tok-number">0xCEC8</span> =&gt; .LV,</span>
<span class="line" id="L339"> <span class="tok-number">0xCEE4</span> =&gt; .LV,</span>
<span class="line" id="L340"> <span class="tok-number">0xCF00</span> =&gt; .LV,</span>
<span class="line" id="L341"> <span class="tok-number">0xCF1C</span> =&gt; .LV,</span>
<span class="line" id="L342"> <span class="tok-number">0xCF38</span> =&gt; .LV,</span>
<span class="line" id="L343"> <span class="tok-number">0xCF54</span> =&gt; .LV,</span>
<span class="line" id="L344"> <span class="tok-number">0xCF70</span> =&gt; .LV,</span>
<span class="line" id="L345"> <span class="tok-number">0xCF8C</span> =&gt; .LV,</span>
<span class="line" id="L346"> <span class="tok-number">0xCFA8</span> =&gt; .LV,</span>
<span class="line" id="L347"> <span class="tok-number">0xCFC4</span> =&gt; .LV,</span>
<span class="line" id="L348"> <span class="tok-number">0xCFE0</span> =&gt; .LV,</span>
<span class="line" id="L349"> <span class="tok-number">0xCFFC</span> =&gt; .LV,</span>
<span class="line" id="L350"> <span class="tok-number">0xD018</span> =&gt; .LV,</span>
<span class="line" id="L351"> <span class="tok-number">0xD034</span> =&gt; .LV,</span>
<span class="line" id="L352"> <span class="tok-number">0xD050</span> =&gt; .LV,</span>
<span class="line" id="L353"> <span class="tok-number">0xD06C</span> =&gt; .LV,</span>
<span class="line" id="L354"> <span class="tok-number">0xD088</span> =&gt; .LV,</span>
<span class="line" id="L355"> <span class="tok-number">0xD0A4</span> =&gt; .LV,</span>
<span class="line" id="L356"> <span class="tok-number">0xD0C0</span> =&gt; .LV,</span>
<span class="line" id="L357"> <span class="tok-number">0xD0DC</span> =&gt; .LV,</span>
<span class="line" id="L358"> <span class="tok-number">0xD0F8</span> =&gt; .LV,</span>
<span class="line" id="L359"> <span class="tok-number">0xD114</span> =&gt; .LV,</span>
<span class="line" id="L360"> <span class="tok-number">0xD130</span> =&gt; .LV,</span>
<span class="line" id="L361"> <span class="tok-number">0xD14C</span> =&gt; .LV,</span>
<span class="line" id="L362"> <span class="tok-number">0xD168</span> =&gt; .LV,</span>
<span class="line" id="L363"> <span class="tok-number">0xD184</span> =&gt; .LV,</span>
<span class="line" id="L364"> <span class="tok-number">0xD1A0</span> =&gt; .LV,</span>
<span class="line" id="L365"> <span class="tok-number">0xD1BC</span> =&gt; .LV,</span>
<span class="line" id="L366"> <span class="tok-number">0xD1D8</span> =&gt; .LV,</span>
<span class="line" id="L367"> <span class="tok-number">0xD1F4</span> =&gt; .LV,</span>
<span class="line" id="L368"> <span class="tok-number">0xD210</span> =&gt; .LV,</span>
<span class="line" id="L369"> <span class="tok-number">0xD22C</span> =&gt; .LV,</span>
<span class="line" id="L370"> <span class="tok-number">0xD248</span> =&gt; .LV,</span>
<span class="line" id="L371"> <span class="tok-number">0xD264</span> =&gt; .LV,</span>
<span class="line" id="L372"> <span class="tok-number">0xD280</span> =&gt; .LV,</span>
<span class="line" id="L373"> <span class="tok-number">0xD29C</span> =&gt; .LV,</span>
<span class="line" id="L374"> <span class="tok-number">0xD2B8</span> =&gt; .LV,</span>
<span class="line" id="L375"> <span class="tok-number">0xD2D4</span> =&gt; .LV,</span>
<span class="line" id="L376"> <span class="tok-number">0xD2F0</span> =&gt; .LV,</span>
<span class="line" id="L377"> <span class="tok-number">0xD30C</span> =&gt; .LV,</span>
<span class="line" id="L378"> <span class="tok-number">0xD328</span> =&gt; .LV,</span>
<span class="line" id="L379"> <span class="tok-number">0xD344</span> =&gt; .LV,</span>
<span class="line" id="L380"> <span class="tok-number">0xD360</span> =&gt; .LV,</span>
<span class="line" id="L381"> <span class="tok-number">0xD37C</span> =&gt; .LV,</span>
<span class="line" id="L382"> <span class="tok-number">0xD398</span> =&gt; .LV,</span>
<span class="line" id="L383"> <span class="tok-number">0xD3B4</span> =&gt; .LV,</span>
<span class="line" id="L384"> <span class="tok-number">0xD3D0</span> =&gt; .LV,</span>
<span class="line" id="L385"> <span class="tok-number">0xD3EC</span> =&gt; .LV,</span>
<span class="line" id="L386"> <span class="tok-number">0xD408</span> =&gt; .LV,</span>
<span class="line" id="L387"> <span class="tok-number">0xD424</span> =&gt; .LV,</span>
<span class="line" id="L388"> <span class="tok-number">0xD440</span> =&gt; .LV,</span>
<span class="line" id="L389"> <span class="tok-number">0xD45C</span> =&gt; .LV,</span>
<span class="line" id="L390"> <span class="tok-number">0xD478</span> =&gt; .LV,</span>
<span class="line" id="L391"> <span class="tok-number">0xD494</span> =&gt; .LV,</span>
<span class="line" id="L392"> <span class="tok-number">0xD4B0</span> =&gt; .LV,</span>
<span class="line" id="L393"> <span class="tok-number">0xD4CC</span> =&gt; .LV,</span>
<span class="line" id="L394"> <span class="tok-number">0xD4E8</span> =&gt; .LV,</span>
<span class="line" id="L395"> <span class="tok-number">0xD504</span> =&gt; .LV,</span>
<span class="line" id="L396"> <span class="tok-number">0xD520</span> =&gt; .LV,</span>
<span class="line" id="L397"> <span class="tok-number">0xD53C</span> =&gt; .LV,</span>
<span class="line" id="L398"> <span class="tok-number">0xD558</span> =&gt; .LV,</span>
<span class="line" id="L399"> <span class="tok-number">0xD574</span> =&gt; .LV,</span>
<span class="line" id="L400"> <span class="tok-number">0xD590</span> =&gt; .LV,</span>
<span class="line" id="L401"> <span class="tok-number">0xD5AC</span> =&gt; .LV,</span>
<span class="line" id="L402"> <span class="tok-number">0xD5C8</span> =&gt; .LV,</span>
<span class="line" id="L403"> <span class="tok-number">0xD5E4</span> =&gt; .LV,</span>
<span class="line" id="L404"> <span class="tok-number">0xD600</span> =&gt; .LV,</span>
<span class="line" id="L405"> <span class="tok-number">0xD61C</span> =&gt; .LV,</span>
<span class="line" id="L406"> <span class="tok-number">0xD638</span> =&gt; .LV,</span>
<span class="line" id="L407"> <span class="tok-number">0xD654</span> =&gt; .LV,</span>
<span class="line" id="L408"> <span class="tok-number">0xD670</span> =&gt; .LV,</span>
<span class="line" id="L409"> <span class="tok-number">0xD68C</span> =&gt; .LV,</span>
<span class="line" id="L410"> <span class="tok-number">0xD6A8</span> =&gt; .LV,</span>
<span class="line" id="L411"> <span class="tok-number">0xD6C4</span> =&gt; .LV,</span>
<span class="line" id="L412"> <span class="tok-number">0xD6E0</span> =&gt; .LV,</span>
<span class="line" id="L413"> <span class="tok-number">0xD6FC</span> =&gt; .LV,</span>
<span class="line" id="L414"> <span class="tok-number">0xD718</span> =&gt; .LV,</span>
<span class="line" id="L415"> <span class="tok-number">0xD734</span> =&gt; .LV,</span>
<span class="line" id="L416"> <span class="tok-number">0xD750</span> =&gt; .LV,</span>
<span class="line" id="L417"> <span class="tok-number">0xD76C</span> =&gt; .LV,</span>
<span class="line" id="L418"> <span class="tok-number">0xD788</span> =&gt; .LV,</span>
<span class="line" id="L419"> <span class="tok-number">0xAC01</span>...<span class="tok-number">0xAC1B</span> =&gt; .LVT,</span>
<span class="line" id="L420"> <span class="tok-number">0xAC1D</span>...<span class="tok-number">0xAC37</span> =&gt; .LVT,</span>
<span class="line" id="L421"> <span class="tok-number">0xAC39</span>...<span class="tok-number">0xAC53</span> =&gt; .LVT,</span>
<span class="line" id="L422"> <span class="tok-number">0xAC55</span>...<span class="tok-number">0xAC6F</span> =&gt; .LVT,</span>
<span class="line" id="L423"> <span class="tok-number">0xAC71</span>...<span class="tok-number">0xAC8B</span> =&gt; .LVT,</span>
<span class="line" id="L424"> <span class="tok-number">0xAC8D</span>...<span class="tok-number">0xACA7</span> =&gt; .LVT,</span>
<span class="line" id="L425"> <span class="tok-number">0xACA9</span>...<span class="tok-number">0xACC3</span> =&gt; .LVT,</span>
<span class="line" id="L426"> <span class="tok-number">0xACC5</span>...<span class="tok-number">0xACDF</span> =&gt; .LVT,</span>
<span class="line" id="L427"> <span class="tok-number">0xACE1</span>...<span class="tok-number">0xACFB</span> =&gt; .LVT,</span>
<span class="line" id="L428"> <span class="tok-number">0xACFD</span>...<span class="tok-number">0xAD17</span> =&gt; .LVT,</span>
<span class="line" id="L429"> <span class="tok-number">0xAD19</span>...<span class="tok-number">0xAD33</span> =&gt; .LVT,</span>
<span class="line" id="L430"> <span class="tok-number">0xAD35</span>...<span class="tok-number">0xAD4F</span> =&gt; .LVT,</span>
<span class="line" id="L431"> <span class="tok-number">0xAD51</span>...<span class="tok-number">0xAD6B</span> =&gt; .LVT,</span>
<span class="line" id="L432"> <span class="tok-number">0xAD6D</span>...<span class="tok-number">0xAD87</span> =&gt; .LVT,</span>
<span class="line" id="L433"> <span class="tok-number">0xAD89</span>...<span class="tok-number">0xADA3</span> =&gt; .LVT,</span>
<span class="line" id="L434"> <span class="tok-number">0xADA5</span>...<span class="tok-number">0xADBF</span> =&gt; .LVT,</span>
<span class="line" id="L435"> <span class="tok-number">0xADC1</span>...<span class="tok-number">0xADDB</span> =&gt; .LVT,</span>
<span class="line" id="L436"> <span class="tok-number">0xADDD</span>...<span class="tok-number">0xADF7</span> =&gt; .LVT,</span>
<span class="line" id="L437"> <span class="tok-number">0xADF9</span>...<span class="tok-number">0xAE13</span> =&gt; .LVT,</span>
<span class="line" id="L438"> <span class="tok-number">0xAE15</span>...<span class="tok-number">0xAE2F</span> =&gt; .LVT,</span>
<span class="line" id="L439"> <span class="tok-number">0xAE31</span>...<span class="tok-number">0xAE4B</span> =&gt; .LVT,</span>
<span class="line" id="L440"> <span class="tok-number">0xAE4D</span>...<span class="tok-number">0xAE67</span> =&gt; .LVT,</span>
<span class="line" id="L441"> <span class="tok-number">0xAE69</span>...<span class="tok-number">0xAE83</span> =&gt; .LVT,</span>
<span class="line" id="L442"> <span class="tok-number">0xAE85</span>...<span class="tok-number">0xAE9F</span> =&gt; .LVT,</span>
<span class="line" id="L443"> <span class="tok-number">0xAEA1</span>...<span class="tok-number">0xAEBB</span> =&gt; .LVT,</span>
<span class="line" id="L444"> <span class="tok-number">0xAEBD</span>...<span class="tok-number">0xAED7</span> =&gt; .LVT,</span>
<span class="line" id="L445"> <span class="tok-number">0xAED9</span>...<span class="tok-number">0xAEF3</span> =&gt; .LVT,</span>
<span class="line" id="L446"> <span class="tok-number">0xAEF5</span>...<span class="tok-number">0xAF0F</span> =&gt; .LVT,</span>
<span class="line" id="L447"> <span class="tok-number">0xAF11</span>...<span class="tok-number">0xAF2B</span> =&gt; .LVT,</span>
<span class="line" id="L448"> <span class="tok-number">0xAF2D</span>...<span class="tok-number">0xAF47</span> =&gt; .LVT,</span>
<span class="line" id="L449"> <span class="tok-number">0xAF49</span>...<span class="tok-number">0xAF63</span> =&gt; .LVT,</span>
<span class="line" id="L450"> <span class="tok-number">0xAF65</span>...<span class="tok-number">0xAF7F</span> =&gt; .LVT,</span>
<span class="line" id="L451"> <span class="tok-number">0xAF81</span>...<span class="tok-number">0xAF9B</span> =&gt; .LVT,</span>
<span class="line" id="L452"> <span class="tok-number">0xAF9D</span>...<span class="tok-number">0xAFB7</span> =&gt; .LVT,</span>
<span class="line" id="L453"> <span class="tok-number">0xAFB9</span>...<span class="tok-number">0xAFD3</span> =&gt; .LVT,</span>
<span class="line" id="L454"> <span class="tok-number">0xAFD5</span>...<span class="tok-number">0xAFEF</span> =&gt; .LVT,</span>
<span class="line" id="L455"> <span class="tok-number">0xAFF1</span>...<span class="tok-number">0xB00B</span> =&gt; .LVT,</span>
<span class="line" id="L456"> <span class="tok-number">0xB00D</span>...<span class="tok-number">0xB027</span> =&gt; .LVT,</span>
<span class="line" id="L457"> <span class="tok-number">0xB029</span>...<span class="tok-number">0xB043</span> =&gt; .LVT,</span>
<span class="line" id="L458"> <span class="tok-number">0xB045</span>...<span class="tok-number">0xB05F</span> =&gt; .LVT,</span>
<span class="line" id="L459"> <span class="tok-number">0xB061</span>...<span class="tok-number">0xB07B</span> =&gt; .LVT,</span>
<span class="line" id="L460"> <span class="tok-number">0xB07D</span>...<span class="tok-number">0xB097</span> =&gt; .LVT,</span>
<span class="line" id="L461"> <span class="tok-number">0xB099</span>...<span class="tok-number">0xB0B3</span> =&gt; .LVT,</span>
<span class="line" id="L462"> <span class="tok-number">0xB0B5</span>...<span class="tok-number">0xB0CF</span> =&gt; .LVT,</span>
<span class="line" id="L463"> <span class="tok-number">0xB0D1</span>...<span class="tok-number">0xB0EB</span> =&gt; .LVT,</span>
<span class="line" id="L464"> <span class="tok-number">0xB0ED</span>...<span class="tok-number">0xB107</span> =&gt; .LVT,</span>
<span class="line" id="L465"> <span class="tok-number">0xB109</span>...<span class="tok-number">0xB123</span> =&gt; .LVT,</span>
<span class="line" id="L466"> <span class="tok-number">0xB125</span>...<span class="tok-number">0xB13F</span> =&gt; .LVT,</span>
<span class="line" id="L467"> <span class="tok-number">0xB141</span>...<span class="tok-number">0xB15B</span> =&gt; .LVT,</span>
<span class="line" id="L468"> <span class="tok-number">0xB15D</span>...<span class="tok-number">0xB177</span> =&gt; .LVT,</span>
<span class="line" id="L469"> <span class="tok-number">0xB179</span>...<span class="tok-number">0xB193</span> =&gt; .LVT,</span>
<span class="line" id="L470"> <span class="tok-number">0xB195</span>...<span class="tok-number">0xB1AF</span> =&gt; .LVT,</span>
<span class="line" id="L471"> <span class="tok-number">0xB1B1</span>...<span class="tok-number">0xB1CB</span> =&gt; .LVT,</span>
<span class="line" id="L472"> <span class="tok-number">0xB1CD</span>...<span class="tok-number">0xB1E7</span> =&gt; .LVT,</span>
<span class="line" id="L473"> <span class="tok-number">0xB1E9</span>...<span class="tok-number">0xB203</span> =&gt; .LVT,</span>
<span class="line" id="L474"> <span class="tok-number">0xB205</span>...<span class="tok-number">0xB21F</span> =&gt; .LVT,</span>
<span class="line" id="L475"> <span class="tok-number">0xB221</span>...<span class="tok-number">0xB23B</span> =&gt; .LVT,</span>
<span class="line" id="L476"> <span class="tok-number">0xB23D</span>...<span class="tok-number">0xB257</span> =&gt; .LVT,</span>
<span class="line" id="L477"> <span class="tok-number">0xB259</span>...<span class="tok-number">0xB273</span> =&gt; .LVT,</span>
<span class="line" id="L478"> <span class="tok-number">0xB275</span>...<span class="tok-number">0xB28F</span> =&gt; .LVT,</span>
<span class="line" id="L479"> <span class="tok-number">0xB291</span>...<span class="tok-number">0xB2AB</span> =&gt; .LVT,</span>
<span class="line" id="L480"> <span class="tok-number">0xB2AD</span>...<span class="tok-number">0xB2C7</span> =&gt; .LVT,</span>
<span class="line" id="L481"> <span class="tok-number">0xB2C9</span>...<span class="tok-number">0xB2E3</span> =&gt; .LVT,</span>
<span class="line" id="L482"> <span class="tok-number">0xB2E5</span>...<span class="tok-number">0xB2FF</span> =&gt; .LVT,</span>
<span class="line" id="L483"> <span class="tok-number">0xB301</span>...<span class="tok-number">0xB31B</span> =&gt; .LVT,</span>
<span class="line" id="L484"> <span class="tok-number">0xB31D</span>...<span class="tok-number">0xB337</span> =&gt; .LVT,</span>
<span class="line" id="L485"> <span class="tok-number">0xB339</span>...<span class="tok-number">0xB353</span> =&gt; .LVT,</span>
<span class="line" id="L486"> <span class="tok-number">0xB355</span>...<span class="tok-number">0xB36F</span> =&gt; .LVT,</span>
<span class="line" id="L487"> <span class="tok-number">0xB371</span>...<span class="tok-number">0xB38B</span> =&gt; .LVT,</span>
<span class="line" id="L488"> <span class="tok-number">0xB38D</span>...<span class="tok-number">0xB3A7</span> =&gt; .LVT,</span>
<span class="line" id="L489"> <span class="tok-number">0xB3A9</span>...<span class="tok-number">0xB3C3</span> =&gt; .LVT,</span>
<span class="line" id="L490"> <span class="tok-number">0xB3C5</span>...<span class="tok-number">0xB3DF</span> =&gt; .LVT,</span>
<span class="line" id="L491"> <span class="tok-number">0xB3E1</span>...<span class="tok-number">0xB3FB</span> =&gt; .LVT,</span>
<span class="line" id="L492"> <span class="tok-number">0xB3FD</span>...<span class="tok-number">0xB417</span> =&gt; .LVT,</span>
<span class="line" id="L493"> <span class="tok-number">0xB419</span>...<span class="tok-number">0xB433</span> =&gt; .LVT,</span>
<span class="line" id="L494"> <span class="tok-number">0xB435</span>...<span class="tok-number">0xB44F</span> =&gt; .LVT,</span>
<span class="line" id="L495"> <span class="tok-number">0xB451</span>...<span class="tok-number">0xB46B</span> =&gt; .LVT,</span>
<span class="line" id="L496"> <span class="tok-number">0xB46D</span>...<span class="tok-number">0xB487</span> =&gt; .LVT,</span>
<span class="line" id="L497"> <span class="tok-number">0xB489</span>...<span class="tok-number">0xB4A3</span> =&gt; .LVT,</span>
<span class="line" id="L498"> <span class="tok-number">0xB4A5</span>...<span class="tok-number">0xB4BF</span> =&gt; .LVT,</span>
<span class="line" id="L499"> <span class="tok-number">0xB4C1</span>...<span class="tok-number">0xB4DB</span> =&gt; .LVT,</span>
<span class="line" id="L500"> <span class="tok-number">0xB4DD</span>...<span class="tok-number">0xB4F7</span> =&gt; .LVT,</span>
<span class="line" id="L501"> <span class="tok-number">0xB4F9</span>...<span class="tok-number">0xB513</span> =&gt; .LVT,</span>
<span class="line" id="L502"> <span class="tok-number">0xB515</span>...<span class="tok-number">0xB52F</span> =&gt; .LVT,</span>
<span class="line" id="L503"> <span class="tok-number">0xB531</span>...<span class="tok-number">0xB54B</span> =&gt; .LVT,</span>
<span class="line" id="L504"> <span class="tok-number">0xB54D</span>...<span class="tok-number">0xB567</span> =&gt; .LVT,</span>
<span class="line" id="L505"> <span class="tok-number">0xB569</span>...<span class="tok-number">0xB583</span> =&gt; .LVT,</span>
<span class="line" id="L506"> <span class="tok-number">0xB585</span>...<span class="tok-number">0xB59F</span> =&gt; .LVT,</span>
<span class="line" id="L507"> <span class="tok-number">0xB5A1</span>...<span class="tok-number">0xB5BB</span> =&gt; .LVT,</span>
<span class="line" id="L508"> <span class="tok-number">0xB5BD</span>...<span class="tok-number">0xB5D7</span> =&gt; .LVT,</span>
<span class="line" id="L509"> <span class="tok-number">0xB5D9</span>...<span class="tok-number">0xB5F3</span> =&gt; .LVT,</span>
<span class="line" id="L510"> <span class="tok-number">0xB5F5</span>...<span class="tok-number">0xB60F</span> =&gt; .LVT,</span>
<span class="line" id="L511"> <span class="tok-number">0xB611</span>...<span class="tok-number">0xB62B</span> =&gt; .LVT,</span>
<span class="line" id="L512"> <span class="tok-number">0xB62D</span>...<span class="tok-number">0xB647</span> =&gt; .LVT,</span>
<span class="line" id="L513"> <span class="tok-number">0xB649</span>...<span class="tok-number">0xB663</span> =&gt; .LVT,</span>
<span class="line" id="L514"> <span class="tok-number">0xB665</span>...<span class="tok-number">0xB67F</span> =&gt; .LVT,</span>
<span class="line" id="L515"> <span class="tok-number">0xB681</span>...<span class="tok-number">0xB69B</span> =&gt; .LVT,</span>
<span class="line" id="L516"> <span class="tok-number">0xB69D</span>...<span class="tok-number">0xB6B7</span> =&gt; .LVT,</span>
<span class="line" id="L517"> <span class="tok-number">0xB6B9</span>...<span class="tok-number">0xB6D3</span> =&gt; .LVT,</span>
<span class="line" id="L518"> <span class="tok-number">0xB6D5</span>...<span class="tok-number">0xB6EF</span> =&gt; .LVT,</span>
<span class="line" id="L519"> <span class="tok-number">0xB6F1</span>...<span class="tok-number">0xB70B</span> =&gt; .LVT,</span>
<span class="line" id="L520"> <span class="tok-number">0xB70D</span>...<span class="tok-number">0xB727</span> =&gt; .LVT,</span>
<span class="line" id="L521"> <span class="tok-number">0xB729</span>...<span class="tok-number">0xB743</span> =&gt; .LVT,</span>
<span class="line" id="L522"> <span class="tok-number">0xB745</span>...<span class="tok-number">0xB75F</span> =&gt; .LVT,</span>
<span class="line" id="L523"> <span class="tok-number">0xB761</span>...<span class="tok-number">0xB77B</span> =&gt; .LVT,</span>
<span class="line" id="L524"> <span class="tok-number">0xB77D</span>...<span class="tok-number">0xB797</span> =&gt; .LVT,</span>
<span class="line" id="L525"> <span class="tok-number">0xB799</span>...<span class="tok-number">0xB7B3</span> =&gt; .LVT,</span>
<span class="line" id="L526"> <span class="tok-number">0xB7B5</span>...<span class="tok-number">0xB7CF</span> =&gt; .LVT,</span>
<span class="line" id="L527"> <span class="tok-number">0xB7D1</span>...<span class="tok-number">0xB7EB</span> =&gt; .LVT,</span>
<span class="line" id="L528"> <span class="tok-number">0xB7ED</span>...<span class="tok-number">0xB807</span> =&gt; .LVT,</span>
<span class="line" id="L529"> <span class="tok-number">0xB809</span>...<span class="tok-number">0xB823</span> =&gt; .LVT,</span>
<span class="line" id="L530"> <span class="tok-number">0xB825</span>...<span class="tok-number">0xB83F</span> =&gt; .LVT,</span>
<span class="line" id="L531"> <span class="tok-number">0xB841</span>...<span class="tok-number">0xB85B</span> =&gt; .LVT,</span>
<span class="line" id="L532"> <span class="tok-number">0xB85D</span>...<span class="tok-number">0xB877</span> =&gt; .LVT,</span>
<span class="line" id="L533"> <span class="tok-number">0xB879</span>...<span class="tok-number">0xB893</span> =&gt; .LVT,</span>
<span class="line" id="L534"> <span class="tok-number">0xB895</span>...<span class="tok-number">0xB8AF</span> =&gt; .LVT,</span>
<span class="line" id="L535"> <span class="tok-number">0xB8B1</span>...<span class="tok-number">0xB8CB</span> =&gt; .LVT,</span>
<span class="line" id="L536"> <span class="tok-number">0xB8CD</span>...<span class="tok-number">0xB8E7</span> =&gt; .LVT,</span>
<span class="line" id="L537"> <span class="tok-number">0xB8E9</span>...<span class="tok-number">0xB903</span> =&gt; .LVT,</span>
<span class="line" id="L538"> <span class="tok-number">0xB905</span>...<span class="tok-number">0xB91F</span> =&gt; .LVT,</span>
<span class="line" id="L539"> <span class="tok-number">0xB921</span>...<span class="tok-number">0xB93B</span> =&gt; .LVT,</span>
<span class="line" id="L540"> <span class="tok-number">0xB93D</span>...<span class="tok-number">0xB957</span> =&gt; .LVT,</span>
<span class="line" id="L541"> <span class="tok-number">0xB959</span>...<span class="tok-number">0xB973</span> =&gt; .LVT,</span>
<span class="line" id="L542"> <span class="tok-number">0xB975</span>...<span class="tok-number">0xB98F</span> =&gt; .LVT,</span>
<span class="line" id="L543"> <span class="tok-number">0xB991</span>...<span class="tok-number">0xB9AB</span> =&gt; .LVT,</span>
<span class="line" id="L544"> <span class="tok-number">0xB9AD</span>...<span class="tok-number">0xB9C7</span> =&gt; .LVT,</span>
<span class="line" id="L545"> <span class="tok-number">0xB9C9</span>...<span class="tok-number">0xB9E3</span> =&gt; .LVT,</span>
<span class="line" id="L546"> <span class="tok-number">0xB9E5</span>...<span class="tok-number">0xB9FF</span> =&gt; .LVT,</span>
<span class="line" id="L547"> <span class="tok-number">0xBA01</span>...<span class="tok-number">0xBA1B</span> =&gt; .LVT,</span>
<span class="line" id="L548"> <span class="tok-number">0xBA1D</span>...<span class="tok-number">0xBA37</span> =&gt; .LVT,</span>
<span class="line" id="L549"> <span class="tok-number">0xBA39</span>...<span class="tok-number">0xBA53</span> =&gt; .LVT,</span>
<span class="line" id="L550"> <span class="tok-number">0xBA55</span>...<span class="tok-number">0xBA6F</span> =&gt; .LVT,</span>
<span class="line" id="L551"> <span class="tok-number">0xBA71</span>...<span class="tok-number">0xBA8B</span> =&gt; .LVT,</span>
<span class="line" id="L552"> <span class="tok-number">0xBA8D</span>...<span class="tok-number">0xBAA7</span> =&gt; .LVT,</span>
<span class="line" id="L553"> <span class="tok-number">0xBAA9</span>...<span class="tok-number">0xBAC3</span> =&gt; .LVT,</span>
<span class="line" id="L554"> <span class="tok-number">0xBAC5</span>...<span class="tok-number">0xBADF</span> =&gt; .LVT,</span>
<span class="line" id="L555"> <span class="tok-number">0xBAE1</span>...<span class="tok-number">0xBAFB</span> =&gt; .LVT,</span>
<span class="line" id="L556"> <span class="tok-number">0xBAFD</span>...<span class="tok-number">0xBB17</span> =&gt; .LVT,</span>
<span class="line" id="L557"> <span class="tok-number">0xBB19</span>...<span class="tok-number">0xBB33</span> =&gt; .LVT,</span>
<span class="line" id="L558"> <span class="tok-number">0xBB35</span>...<span class="tok-number">0xBB4F</span> =&gt; .LVT,</span>
<span class="line" id="L559"> <span class="tok-number">0xBB51</span>...<span class="tok-number">0xBB6B</span> =&gt; .LVT,</span>
<span class="line" id="L560"> <span class="tok-number">0xBB6D</span>...<span class="tok-number">0xBB87</span> =&gt; .LVT,</span>
<span class="line" id="L561"> <span class="tok-number">0xBB89</span>...<span class="tok-number">0xBBA3</span> =&gt; .LVT,</span>
<span class="line" id="L562"> <span class="tok-number">0xBBA5</span>...<span class="tok-number">0xBBBF</span> =&gt; .LVT,</span>
<span class="line" id="L563"> <span class="tok-number">0xBBC1</span>...<span class="tok-number">0xBBDB</span> =&gt; .LVT,</span>
<span class="line" id="L564"> <span class="tok-number">0xBBDD</span>...<span class="tok-number">0xBBF7</span> =&gt; .LVT,</span>
<span class="line" id="L565"> <span class="tok-number">0xBBF9</span>...<span class="tok-number">0xBC13</span> =&gt; .LVT,</span>
<span class="line" id="L566"> <span class="tok-number">0xBC15</span>...<span class="tok-number">0xBC2F</span> =&gt; .LVT,</span>
<span class="line" id="L567"> <span class="tok-number">0xBC31</span>...<span class="tok-number">0xBC4B</span> =&gt; .LVT,</span>
<span class="line" id="L568"> <span class="tok-number">0xBC4D</span>...<span class="tok-number">0xBC67</span> =&gt; .LVT,</span>
<span class="line" id="L569"> <span class="tok-number">0xBC69</span>...<span class="tok-number">0xBC83</span> =&gt; .LVT,</span>
<span class="line" id="L570"> <span class="tok-number">0xBC85</span>...<span class="tok-number">0xBC9F</span> =&gt; .LVT,</span>
<span class="line" id="L571"> <span class="tok-number">0xBCA1</span>...<span class="tok-number">0xBCBB</span> =&gt; .LVT,</span>
<span class="line" id="L572"> <span class="tok-number">0xBCBD</span>...<span class="tok-number">0xBCD7</span> =&gt; .LVT,</span>
<span class="line" id="L573"> <span class="tok-number">0xBCD9</span>...<span class="tok-number">0xBCF3</span> =&gt; .LVT,</span>
<span class="line" id="L574"> <span class="tok-number">0xBCF5</span>...<span class="tok-number">0xBD0F</span> =&gt; .LVT,</span>
<span class="line" id="L575"> <span class="tok-number">0xBD11</span>...<span class="tok-number">0xBD2B</span> =&gt; .LVT,</span>
<span class="line" id="L576"> <span class="tok-number">0xBD2D</span>...<span class="tok-number">0xBD47</span> =&gt; .LVT,</span>
<span class="line" id="L577"> <span class="tok-number">0xBD49</span>...<span class="tok-number">0xBD63</span> =&gt; .LVT,</span>
<span class="line" id="L578"> <span class="tok-number">0xBD65</span>...<span class="tok-number">0xBD7F</span> =&gt; .LVT,</span>
<span class="line" id="L579"> <span class="tok-number">0xBD81</span>...<span class="tok-number">0xBD9B</span> =&gt; .LVT,</span>
<span class="line" id="L580"> <span class="tok-number">0xBD9D</span>...<span class="tok-number">0xBDB7</span> =&gt; .LVT,</span>
<span class="line" id="L581"> <span class="tok-number">0xBDB9</span>...<span class="tok-number">0xBDD3</span> =&gt; .LVT,</span>
<span class="line" id="L582"> <span class="tok-number">0xBDD5</span>...<span class="tok-number">0xBDEF</span> =&gt; .LVT,</span>
<span class="line" id="L583"> <span class="tok-number">0xBDF1</span>...<span class="tok-number">0xBE0B</span> =&gt; .LVT,</span>
<span class="line" id="L584"> <span class="tok-number">0xBE0D</span>...<span class="tok-number">0xBE27</span> =&gt; .LVT,</span>
<span class="line" id="L585"> <span class="tok-number">0xBE29</span>...<span class="tok-number">0xBE43</span> =&gt; .LVT,</span>
<span class="line" id="L586"> <span class="tok-number">0xBE45</span>...<span class="tok-number">0xBE5F</span> =&gt; .LVT,</span>
<span class="line" id="L587"> <span class="tok-number">0xBE61</span>...<span class="tok-number">0xBE7B</span> =&gt; .LVT,</span>
<span class="line" id="L588"> <span class="tok-number">0xBE7D</span>...<span class="tok-number">0xBE97</span> =&gt; .LVT,</span>
<span class="line" id="L589"> <span class="tok-number">0xBE99</span>...<span class="tok-number">0xBEB3</span> =&gt; .LVT,</span>
<span class="line" id="L590"> <span class="tok-number">0xBEB5</span>...<span class="tok-number">0xBECF</span> =&gt; .LVT,</span>
<span class="line" id="L591"> <span class="tok-number">0xBED1</span>...<span class="tok-number">0xBEEB</span> =&gt; .LVT,</span>
<span class="line" id="L592"> <span class="tok-number">0xBEED</span>...<span class="tok-number">0xBF07</span> =&gt; .LVT,</span>
<span class="line" id="L593"> <span class="tok-number">0xBF09</span>...<span class="tok-number">0xBF23</span> =&gt; .LVT,</span>
<span class="line" id="L594"> <span class="tok-number">0xBF25</span>...<span class="tok-number">0xBF3F</span> =&gt; .LVT,</span>
<span class="line" id="L595"> <span class="tok-number">0xBF41</span>...<span class="tok-number">0xBF5B</span> =&gt; .LVT,</span>
<span class="line" id="L596"> <span class="tok-number">0xBF5D</span>...<span class="tok-number">0xBF77</span> =&gt; .LVT,</span>
<span class="line" id="L597"> <span class="tok-number">0xBF79</span>...<span class="tok-number">0xBF93</span> =&gt; .LVT,</span>
<span class="line" id="L598"> <span class="tok-number">0xBF95</span>...<span class="tok-number">0xBFAF</span> =&gt; .LVT,</span>
<span class="line" id="L599"> <span class="tok-number">0xBFB1</span>...<span class="tok-number">0xBFCB</span> =&gt; .LVT,</span>
<span class="line" id="L600"> <span class="tok-number">0xBFCD</span>...<span class="tok-number">0xBFE7</span> =&gt; .LVT,</span>
<span class="line" id="L601"> <span class="tok-number">0xBFE9</span>...<span class="tok-number">0xC003</span> =&gt; .LVT,</span>
<span class="line" id="L602"> <span class="tok-number">0xC005</span>...<span class="tok-number">0xC01F</span> =&gt; .LVT,</span>
<span class="line" id="L603"> <span class="tok-number">0xC021</span>...<span class="tok-number">0xC03B</span> =&gt; .LVT,</span>
<span class="line" id="L604"> <span class="tok-number">0xC03D</span>...<span class="tok-number">0xC057</span> =&gt; .LVT,</span>
<span class="line" id="L605"> <span class="tok-number">0xC059</span>...<span class="tok-number">0xC073</span> =&gt; .LVT,</span>
<span class="line" id="L606"> <span class="tok-number">0xC075</span>...<span class="tok-number">0xC08F</span> =&gt; .LVT,</span>
<span class="line" id="L607"> <span class="tok-number">0xC091</span>...<span class="tok-number">0xC0AB</span> =&gt; .LVT,</span>
<span class="line" id="L608"> <span class="tok-number">0xC0AD</span>...<span class="tok-number">0xC0C7</span> =&gt; .LVT,</span>
<span class="line" id="L609"> <span class="tok-number">0xC0C9</span>...<span class="tok-number">0xC0E3</span> =&gt; .LVT,</span>
<span class="line" id="L610"> <span class="tok-number">0xC0E5</span>...<span class="tok-number">0xC0FF</span> =&gt; .LVT,</span>
<span class="line" id="L611"> <span class="tok-number">0xC101</span>...<span class="tok-number">0xC11B</span> =&gt; .LVT,</span>
<span class="line" id="L612"> <span class="tok-number">0xC11D</span>...<span class="tok-number">0xC137</span> =&gt; .LVT,</span>
<span class="line" id="L613"> <span class="tok-number">0xC139</span>...<span class="tok-number">0xC153</span> =&gt; .LVT,</span>
<span class="line" id="L614"> <span class="tok-number">0xC155</span>...<span class="tok-number">0xC16F</span> =&gt; .LVT,</span>
<span class="line" id="L615"> <span class="tok-number">0xC171</span>...<span class="tok-number">0xC18B</span> =&gt; .LVT,</span>
<span class="line" id="L616"> <span class="tok-number">0xC18D</span>...<span class="tok-number">0xC1A7</span> =&gt; .LVT,</span>
<span class="line" id="L617"> <span class="tok-number">0xC1A9</span>...<span class="tok-number">0xC1C3</span> =&gt; .LVT,</span>
<span class="line" id="L618"> <span class="tok-number">0xC1C5</span>...<span class="tok-number">0xC1DF</span> =&gt; .LVT,</span>
<span class="line" id="L619"> <span class="tok-number">0xC1E1</span>...<span class="tok-number">0xC1FB</span> =&gt; .LVT,</span>
<span class="line" id="L620"> <span class="tok-number">0xC1FD</span>...<span class="tok-number">0xC217</span> =&gt; .LVT,</span>
<span class="line" id="L621"> <span class="tok-number">0xC219</span>...<span class="tok-number">0xC233</span> =&gt; .LVT,</span>
<span class="line" id="L622"> <span class="tok-number">0xC235</span>...<span class="tok-number">0xC24F</span> =&gt; .LVT,</span>
<span class="line" id="L623"> <span class="tok-number">0xC251</span>...<span class="tok-number">0xC26B</span> =&gt; .LVT,</span>
<span class="line" id="L624"> <span class="tok-number">0xC26D</span>...<span class="tok-number">0xC287</span> =&gt; .LVT,</span>
<span class="line" id="L625"> <span class="tok-number">0xC289</span>...<span class="tok-number">0xC2A3</span> =&gt; .LVT,</span>
<span class="line" id="L626"> <span class="tok-number">0xC2A5</span>...<span class="tok-number">0xC2BF</span> =&gt; .LVT,</span>
<span class="line" id="L627"> <span class="tok-number">0xC2C1</span>...<span class="tok-number">0xC2DB</span> =&gt; .LVT,</span>
<span class="line" id="L628"> <span class="tok-number">0xC2DD</span>...<span class="tok-number">0xC2F7</span> =&gt; .LVT,</span>
<span class="line" id="L629"> <span class="tok-number">0xC2F9</span>...<span class="tok-number">0xC313</span> =&gt; .LVT,</span>
<span class="line" id="L630"> <span class="tok-number">0xC315</span>...<span class="tok-number">0xC32F</span> =&gt; .LVT,</span>
<span class="line" id="L631"> <span class="tok-number">0xC331</span>...<span class="tok-number">0xC34B</span> =&gt; .LVT,</span>
<span class="line" id="L632"> <span class="tok-number">0xC34D</span>...<span class="tok-number">0xC367</span> =&gt; .LVT,</span>
<span class="line" id="L633"> <span class="tok-number">0xC369</span>...<span class="tok-number">0xC383</span> =&gt; .LVT,</span>
<span class="line" id="L634"> <span class="tok-number">0xC385</span>...<span class="tok-number">0xC39F</span> =&gt; .LVT,</span>
<span class="line" id="L635"> <span class="tok-number">0xC3A1</span>...<span class="tok-number">0xC3BB</span> =&gt; .LVT,</span>
<span class="line" id="L636"> <span class="tok-number">0xC3BD</span>...<span class="tok-number">0xC3D7</span> =&gt; .LVT,</span>
<span class="line" id="L637"> <span class="tok-number">0xC3D9</span>...<span class="tok-number">0xC3F3</span> =&gt; .LVT,</span>
<span class="line" id="L638"> <span class="tok-number">0xC3F5</span>...<span class="tok-number">0xC40F</span> =&gt; .LVT,</span>
<span class="line" id="L639"> <span class="tok-number">0xC411</span>...<span class="tok-number">0xC42B</span> =&gt; .LVT,</span>
<span class="line" id="L640"> <span class="tok-number">0xC42D</span>...<span class="tok-number">0xC447</span> =&gt; .LVT,</span>
<span class="line" id="L641"> <span class="tok-number">0xC449</span>...<span class="tok-number">0xC463</span> =&gt; .LVT,</span>
<span class="line" id="L642"> <span class="tok-number">0xC465</span>...<span class="tok-number">0xC47F</span> =&gt; .LVT,</span>
<span class="line" id="L643"> <span class="tok-number">0xC481</span>...<span class="tok-number">0xC49B</span> =&gt; .LVT,</span>
<span class="line" id="L644"> <span class="tok-number">0xC49D</span>...<span class="tok-number">0xC4B7</span> =&gt; .LVT,</span>
<span class="line" id="L645"> <span class="tok-number">0xC4B9</span>...<span class="tok-number">0xC4D3</span> =&gt; .LVT,</span>
<span class="line" id="L646"> <span class="tok-number">0xC4D5</span>...<span class="tok-number">0xC4EF</span> =&gt; .LVT,</span>
<span class="line" id="L647"> <span class="tok-number">0xC4F1</span>...<span class="tok-number">0xC50B</span> =&gt; .LVT,</span>
<span class="line" id="L648"> <span class="tok-number">0xC50D</span>...<span class="tok-number">0xC527</span> =&gt; .LVT,</span>
<span class="line" id="L649"> <span class="tok-number">0xC529</span>...<span class="tok-number">0xC543</span> =&gt; .LVT,</span>
<span class="line" id="L650"> <span class="tok-number">0xC545</span>...<span class="tok-number">0xC55F</span> =&gt; .LVT,</span>
<span class="line" id="L651"> <span class="tok-number">0xC561</span>...<span class="tok-number">0xC57B</span> =&gt; .LVT,</span>
<span class="line" id="L652"> <span class="tok-number">0xC57D</span>...<span class="tok-number">0xC597</span> =&gt; .LVT,</span>
<span class="line" id="L653"> <span class="tok-number">0xC599</span>...<span class="tok-number">0xC5B3</span> =&gt; .LVT,</span>
<span class="line" id="L654"> <span class="tok-number">0xC5B5</span>...<span class="tok-number">0xC5CF</span> =&gt; .LVT,</span>
<span class="line" id="L655"> <span class="tok-number">0xC5D1</span>...<span class="tok-number">0xC5EB</span> =&gt; .LVT,</span>
<span class="line" id="L656"> <span class="tok-number">0xC5ED</span>...<span class="tok-number">0xC607</span> =&gt; .LVT,</span>
<span class="line" id="L657"> <span class="tok-number">0xC609</span>...<span class="tok-number">0xC623</span> =&gt; .LVT,</span>
<span class="line" id="L658"> <span class="tok-number">0xC625</span>...<span class="tok-number">0xC63F</span> =&gt; .LVT,</span>
<span class="line" id="L659"> <span class="tok-number">0xC641</span>...<span class="tok-number">0xC65B</span> =&gt; .LVT,</span>
<span class="line" id="L660"> <span class="tok-number">0xC65D</span>...<span class="tok-number">0xC677</span> =&gt; .LVT,</span>
<span class="line" id="L661"> <span class="tok-number">0xC679</span>...<span class="tok-number">0xC693</span> =&gt; .LVT,</span>
<span class="line" id="L662"> <span class="tok-number">0xC695</span>...<span class="tok-number">0xC6AF</span> =&gt; .LVT,</span>
<span class="line" id="L663"> <span class="tok-number">0xC6B1</span>...<span class="tok-number">0xC6CB</span> =&gt; .LVT,</span>
<span class="line" id="L664"> <span class="tok-number">0xC6CD</span>...<span class="tok-number">0xC6E7</span> =&gt; .LVT,</span>
<span class="line" id="L665"> <span class="tok-number">0xC6E9</span>...<span class="tok-number">0xC703</span> =&gt; .LVT,</span>
<span class="line" id="L666"> <span class="tok-number">0xC705</span>...<span class="tok-number">0xC71F</span> =&gt; .LVT,</span>
<span class="line" id="L667"> <span class="tok-number">0xC721</span>...<span class="tok-number">0xC73B</span> =&gt; .LVT,</span>
<span class="line" id="L668"> <span class="tok-number">0xC73D</span>...<span class="tok-number">0xC757</span> =&gt; .LVT,</span>
<span class="line" id="L669"> <span class="tok-number">0xC759</span>...<span class="tok-number">0xC773</span> =&gt; .LVT,</span>
<span class="line" id="L670"> <span class="tok-number">0xC775</span>...<span class="tok-number">0xC78F</span> =&gt; .LVT,</span>
<span class="line" id="L671"> <span class="tok-number">0xC791</span>...<span class="tok-number">0xC7AB</span> =&gt; .LVT,</span>
<span class="line" id="L672"> <span class="tok-number">0xC7AD</span>...<span class="tok-number">0xC7C7</span> =&gt; .LVT,</span>
<span class="line" id="L673"> <span class="tok-number">0xC7C9</span>...<span class="tok-number">0xC7E3</span> =&gt; .LVT,</span>
<span class="line" id="L674"> <span class="tok-number">0xC7E5</span>...<span class="tok-number">0xC7FF</span> =&gt; .LVT,</span>
<span class="line" id="L675"> <span class="tok-number">0xC801</span>...<span class="tok-number">0xC81B</span> =&gt; .LVT,</span>
<span class="line" id="L676"> <span class="tok-number">0xC81D</span>...<span class="tok-number">0xC837</span> =&gt; .LVT,</span>
<span class="line" id="L677"> <span class="tok-number">0xC839</span>...<span class="tok-number">0xC853</span> =&gt; .LVT,</span>
<span class="line" id="L678"> <span class="tok-number">0xC855</span>...<span class="tok-number">0xC86F</span> =&gt; .LVT,</span>
<span class="line" id="L679"> <span class="tok-number">0xC871</span>...<span class="tok-number">0xC88B</span> =&gt; .LVT,</span>
<span class="line" id="L680"> <span class="tok-number">0xC88D</span>...<span class="tok-number">0xC8A7</span> =&gt; .LVT,</span>
<span class="line" id="L681"> <span class="tok-number">0xC8A9</span>...<span class="tok-number">0xC8C3</span> =&gt; .LVT,</span>
<span class="line" id="L682"> <span class="tok-number">0xC8C5</span>...<span class="tok-number">0xC8DF</span> =&gt; .LVT,</span>
<span class="line" id="L683"> <span class="tok-number">0xC8E1</span>...<span class="tok-number">0xC8FB</span> =&gt; .LVT,</span>
<span class="line" id="L684"> <span class="tok-number">0xC8FD</span>...<span class="tok-number">0xC917</span> =&gt; .LVT,</span>
<span class="line" id="L685"> <span class="tok-number">0xC919</span>...<span class="tok-number">0xC933</span> =&gt; .LVT,</span>
<span class="line" id="L686"> <span class="tok-number">0xC935</span>...<span class="tok-number">0xC94F</span> =&gt; .LVT,</span>
<span class="line" id="L687"> <span class="tok-number">0xC951</span>...<span class="tok-number">0xC96B</span> =&gt; .LVT,</span>
<span class="line" id="L688"> <span class="tok-number">0xC96D</span>...<span class="tok-number">0xC987</span> =&gt; .LVT,</span>
<span class="line" id="L689"> <span class="tok-number">0xC989</span>...<span class="tok-number">0xC9A3</span> =&gt; .LVT,</span>
<span class="line" id="L690"> <span class="tok-number">0xC9A5</span>...<span class="tok-number">0xC9BF</span> =&gt; .LVT,</span>
<span class="line" id="L691"> <span class="tok-number">0xC9C1</span>...<span class="tok-number">0xC9DB</span> =&gt; .LVT,</span>
<span class="line" id="L692"> <span class="tok-number">0xC9DD</span>...<span class="tok-number">0xC9F7</span> =&gt; .LVT,</span>
<span class="line" id="L693"> <span class="tok-number">0xC9F9</span>...<span class="tok-number">0xCA13</span> =&gt; .LVT,</span>
<span class="line" id="L694"> <span class="tok-number">0xCA15</span>...<span class="tok-number">0xCA2F</span> =&gt; .LVT,</span>
<span class="line" id="L695"> <span class="tok-number">0xCA31</span>...<span class="tok-number">0xCA4B</span> =&gt; .LVT,</span>
<span class="line" id="L696"> <span class="tok-number">0xCA4D</span>...<span class="tok-number">0xCA67</span> =&gt; .LVT,</span>
<span class="line" id="L697"> <span class="tok-number">0xCA69</span>...<span class="tok-number">0xCA83</span> =&gt; .LVT,</span>
<span class="line" id="L698"> <span class="tok-number">0xCA85</span>...<span class="tok-number">0xCA9F</span> =&gt; .LVT,</span>
<span class="line" id="L699"> <span class="tok-number">0xCAA1</span>...<span class="tok-number">0xCABB</span> =&gt; .LVT,</span>
<span class="line" id="L700"> <span class="tok-number">0xCABD</span>...<span class="tok-number">0xCAD7</span> =&gt; .LVT,</span>
<span class="line" id="L701"> <span class="tok-number">0xCAD9</span>...<span class="tok-number">0xCAF3</span> =&gt; .LVT,</span>
<span class="line" id="L702"> <span class="tok-number">0xCAF5</span>...<span class="tok-number">0xCB0F</span> =&gt; .LVT,</span>
<span class="line" id="L703"> <span class="tok-number">0xCB11</span>...<span class="tok-number">0xCB2B</span> =&gt; .LVT,</span>
<span class="line" id="L704"> <span class="tok-number">0xCB2D</span>...<span class="tok-number">0xCB47</span> =&gt; .LVT,</span>
<span class="line" id="L705"> <span class="tok-number">0xCB49</span>...<span class="tok-number">0xCB63</span> =&gt; .LVT,</span>
<span class="line" id="L706"> <span class="tok-number">0xCB65</span>...<span class="tok-number">0xCB7F</span> =&gt; .LVT,</span>
<span class="line" id="L707"> <span class="tok-number">0xCB81</span>...<span class="tok-number">0xCB9B</span> =&gt; .LVT,</span>
<span class="line" id="L708"> <span class="tok-number">0xCB9D</span>...<span class="tok-number">0xCBB7</span> =&gt; .LVT,</span>
<span class="line" id="L709"> <span class="tok-number">0xCBB9</span>...<span class="tok-number">0xCBD3</span> =&gt; .LVT,</span>
<span class="line" id="L710"> <span class="tok-number">0xCBD5</span>...<span class="tok-number">0xCBEF</span> =&gt; .LVT,</span>
<span class="line" id="L711"> <span class="tok-number">0xCBF1</span>...<span class="tok-number">0xCC0B</span> =&gt; .LVT,</span>
<span class="line" id="L712"> <span class="tok-number">0xCC0D</span>...<span class="tok-number">0xCC27</span> =&gt; .LVT,</span>
<span class="line" id="L713"> <span class="tok-number">0xCC29</span>...<span class="tok-number">0xCC43</span> =&gt; .LVT,</span>
<span class="line" id="L714"> <span class="tok-number">0xCC45</span>...<span class="tok-number">0xCC5F</span> =&gt; .LVT,</span>
<span class="line" id="L715"> <span class="tok-number">0xCC61</span>...<span class="tok-number">0xCC7B</span> =&gt; .LVT,</span>
<span class="line" id="L716"> <span class="tok-number">0xCC7D</span>...<span class="tok-number">0xCC97</span> =&gt; .LVT,</span>
<span class="line" id="L717"> <span class="tok-number">0xCC99</span>...<span class="tok-number">0xCCB3</span> =&gt; .LVT,</span>
<span class="line" id="L718"> <span class="tok-number">0xCCB5</span>...<span class="tok-number">0xCCCF</span> =&gt; .LVT,</span>
<span class="line" id="L719"> <span class="tok-number">0xCCD1</span>...<span class="tok-number">0xCCEB</span> =&gt; .LVT,</span>
<span class="line" id="L720"> <span class="tok-number">0xCCED</span>...<span class="tok-number">0xCD07</span> =&gt; .LVT,</span>
<span class="line" id="L721"> <span class="tok-number">0xCD09</span>...<span class="tok-number">0xCD23</span> =&gt; .LVT,</span>
<span class="line" id="L722"> <span class="tok-number">0xCD25</span>...<span class="tok-number">0xCD3F</span> =&gt; .LVT,</span>
<span class="line" id="L723"> <span class="tok-number">0xCD41</span>...<span class="tok-number">0xCD5B</span> =&gt; .LVT,</span>
<span class="line" id="L724"> <span class="tok-number">0xCD5D</span>...<span class="tok-number">0xCD77</span> =&gt; .LVT,</span>
<span class="line" id="L725"> <span class="tok-number">0xCD79</span>...<span class="tok-number">0xCD93</span> =&gt; .LVT,</span>
<span class="line" id="L726"> <span class="tok-number">0xCD95</span>...<span class="tok-number">0xCDAF</span> =&gt; .LVT,</span>
<span class="line" id="L727"> <span class="tok-number">0xCDB1</span>...<span class="tok-number">0xCDCB</span> =&gt; .LVT,</span>
<span class="line" id="L728"> <span class="tok-number">0xCDCD</span>...<span class="tok-number">0xCDE7</span> =&gt; .LVT,</span>
<span class="line" id="L729"> <span class="tok-number">0xCDE9</span>...<span class="tok-number">0xCE03</span> =&gt; .LVT,</span>
<span class="line" id="L730"> <span class="tok-number">0xCE05</span>...<span class="tok-number">0xCE1F</span> =&gt; .LVT,</span>
<span class="line" id="L731"> <span class="tok-number">0xCE21</span>...<span class="tok-number">0xCE3B</span> =&gt; .LVT,</span>
<span class="line" id="L732"> <span class="tok-number">0xCE3D</span>...<span class="tok-number">0xCE57</span> =&gt; .LVT,</span>
<span class="line" id="L733"> <span class="tok-number">0xCE59</span>...<span class="tok-number">0xCE73</span> =&gt; .LVT,</span>
<span class="line" id="L734"> <span class="tok-number">0xCE75</span>...<span class="tok-number">0xCE8F</span> =&gt; .LVT,</span>
<span class="line" id="L735"> <span class="tok-number">0xCE91</span>...<span class="tok-number">0xCEAB</span> =&gt; .LVT,</span>
<span class="line" id="L736"> <span class="tok-number">0xCEAD</span>...<span class="tok-number">0xCEC7</span> =&gt; .LVT,</span>
<span class="line" id="L737"> <span class="tok-number">0xCEC9</span>...<span class="tok-number">0xCEE3</span> =&gt; .LVT,</span>
<span class="line" id="L738"> <span class="tok-number">0xCEE5</span>...<span class="tok-number">0xCEFF</span> =&gt; .LVT,</span>
<span class="line" id="L739"> <span class="tok-number">0xCF01</span>...<span class="tok-number">0xCF1B</span> =&gt; .LVT,</span>
<span class="line" id="L740"> <span class="tok-number">0xCF1D</span>...<span class="tok-number">0xCF37</span> =&gt; .LVT,</span>
<span class="line" id="L741"> <span class="tok-number">0xCF39</span>...<span class="tok-number">0xCF53</span> =&gt; .LVT,</span>
<span class="line" id="L742"> <span class="tok-number">0xCF55</span>...<span class="tok-number">0xCF6F</span> =&gt; .LVT,</span>
<span class="line" id="L743"> <span class="tok-number">0xCF71</span>...<span class="tok-number">0xCF8B</span> =&gt; .LVT,</span>
<span class="line" id="L744"> <span class="tok-number">0xCF8D</span>...<span class="tok-number">0xCFA7</span> =&gt; .LVT,</span>
<span class="line" id="L745"> <span class="tok-number">0xCFA9</span>...<span class="tok-number">0xCFC3</span> =&gt; .LVT,</span>
<span class="line" id="L746"> <span class="tok-number">0xCFC5</span>...<span class="tok-number">0xCFDF</span> =&gt; .LVT,</span>
<span class="line" id="L747"> <span class="tok-number">0xCFE1</span>...<span class="tok-number">0xCFFB</span> =&gt; .LVT,</span>
<span class="line" id="L748"> <span class="tok-number">0xCFFD</span>...<span class="tok-number">0xD017</span> =&gt; .LVT,</span>
<span class="line" id="L749"> <span class="tok-number">0xD019</span>...<span class="tok-number">0xD033</span> =&gt; .LVT,</span>
<span class="line" id="L750"> <span class="tok-number">0xD035</span>...<span class="tok-number">0xD04F</span> =&gt; .LVT,</span>
<span class="line" id="L751"> <span class="tok-number">0xD051</span>...<span class="tok-number">0xD06B</span> =&gt; .LVT,</span>
<span class="line" id="L752"> <span class="tok-number">0xD06D</span>...<span class="tok-number">0xD087</span> =&gt; .LVT,</span>
<span class="line" id="L753"> <span class="tok-number">0xD089</span>...<span class="tok-number">0xD0A3</span> =&gt; .LVT,</span>
<span class="line" id="L754"> <span class="tok-number">0xD0A5</span>...<span class="tok-number">0xD0BF</span> =&gt; .LVT,</span>
<span class="line" id="L755"> <span class="tok-number">0xD0C1</span>...<span class="tok-number">0xD0DB</span> =&gt; .LVT,</span>
<span class="line" id="L756"> <span class="tok-number">0xD0DD</span>...<span class="tok-number">0xD0F7</span> =&gt; .LVT,</span>
<span class="line" id="L757"> <span class="tok-number">0xD0F9</span>...<span class="tok-number">0xD113</span> =&gt; .LVT,</span>
<span class="line" id="L758"> <span class="tok-number">0xD115</span>...<span class="tok-number">0xD12F</span> =&gt; .LVT,</span>
<span class="line" id="L759"> <span class="tok-number">0xD131</span>...<span class="tok-number">0xD14B</span> =&gt; .LVT,</span>
<span class="line" id="L760"> <span class="tok-number">0xD14D</span>...<span class="tok-number">0xD167</span> =&gt; .LVT,</span>
<span class="line" id="L761"> <span class="tok-number">0xD169</span>...<span class="tok-number">0xD183</span> =&gt; .LVT,</span>
<span class="line" id="L762"> <span class="tok-number">0xD185</span>...<span class="tok-number">0xD19F</span> =&gt; .LVT,</span>
<span class="line" id="L763"> <span class="tok-number">0xD1A1</span>...<span class="tok-number">0xD1BB</span> =&gt; .LVT,</span>
<span class="line" id="L764"> <span class="tok-number">0xD1BD</span>...<span class="tok-number">0xD1D7</span> =&gt; .LVT,</span>
<span class="line" id="L765"> <span class="tok-number">0xD1D9</span>...<span class="tok-number">0xD1F3</span> =&gt; .LVT,</span>
<span class="line" id="L766"> <span class="tok-number">0xD1F5</span>...<span class="tok-number">0xD20F</span> =&gt; .LVT,</span>
<span class="line" id="L767"> <span class="tok-number">0xD211</span>...<span class="tok-number">0xD22B</span> =&gt; .LVT,</span>
<span class="line" id="L768"> <span class="tok-number">0xD22D</span>...<span class="tok-number">0xD247</span> =&gt; .LVT,</span>
<span class="line" id="L769"> <span class="tok-number">0xD249</span>...<span class="tok-number">0xD263</span> =&gt; .LVT,</span>
<span class="line" id="L770"> <span class="tok-number">0xD265</span>...<span class="tok-number">0xD27F</span> =&gt; .LVT,</span>
<span class="line" id="L771"> <span class="tok-number">0xD281</span>...<span class="tok-number">0xD29B</span> =&gt; .LVT,</span>
<span class="line" id="L772"> <span class="tok-number">0xD29D</span>...<span class="tok-number">0xD2B7</span> =&gt; .LVT,</span>
<span class="line" id="L773"> <span class="tok-number">0xD2B9</span>...<span class="tok-number">0xD2D3</span> =&gt; .LVT,</span>
<span class="line" id="L774"> <span class="tok-number">0xD2D5</span>...<span class="tok-number">0xD2EF</span> =&gt; .LVT,</span>
<span class="line" id="L775"> <span class="tok-number">0xD2F1</span>...<span class="tok-number">0xD30B</span> =&gt; .LVT,</span>
<span class="line" id="L776"> <span class="tok-number">0xD30D</span>...<span class="tok-number">0xD327</span> =&gt; .LVT,</span>
<span class="line" id="L777"> <span class="tok-number">0xD329</span>...<span class="tok-number">0xD343</span> =&gt; .LVT,</span>
<span class="line" id="L778"> <span class="tok-number">0xD345</span>...<span class="tok-number">0xD35F</span> =&gt; .LVT,</span>
<span class="line" id="L779"> <span class="tok-number">0xD361</span>...<span class="tok-number">0xD37B</span> =&gt; .LVT,</span>
<span class="line" id="L780"> <span class="tok-number">0xD37D</span>...<span class="tok-number">0xD397</span> =&gt; .LVT,</span>
<span class="line" id="L781"> <span class="tok-number">0xD399</span>...<span class="tok-number">0xD3B3</span> =&gt; .LVT,</span>
<span class="line" id="L782"> <span class="tok-number">0xD3B5</span>...<span class="tok-number">0xD3CF</span> =&gt; .LVT,</span>
<span class="line" id="L783"> <span class="tok-number">0xD3D1</span>...<span class="tok-number">0xD3EB</span> =&gt; .LVT,</span>
<span class="line" id="L784"> <span class="tok-number">0xD3ED</span>...<span class="tok-number">0xD407</span> =&gt; .LVT,</span>
<span class="line" id="L785"> <span class="tok-number">0xD409</span>...<span class="tok-number">0xD423</span> =&gt; .LVT,</span>
<span class="line" id="L786"> <span class="tok-number">0xD425</span>...<span class="tok-number">0xD43F</span> =&gt; .LVT,</span>
<span class="line" id="L787"> <span class="tok-number">0xD441</span>...<span class="tok-number">0xD45B</span> =&gt; .LVT,</span>
<span class="line" id="L788"> <span class="tok-number">0xD45D</span>...<span class="tok-number">0xD477</span> =&gt; .LVT,</span>
<span class="line" id="L789"> <span class="tok-number">0xD479</span>...<span class="tok-number">0xD493</span> =&gt; .LVT,</span>
<span class="line" id="L790"> <span class="tok-number">0xD495</span>...<span class="tok-number">0xD4AF</span> =&gt; .LVT,</span>
<span class="line" id="L791"> <span class="tok-number">0xD4B1</span>...<span class="tok-number">0xD4CB</span> =&gt; .LVT,</span>
<span class="line" id="L792"> <span class="tok-number">0xD4CD</span>...<span class="tok-number">0xD4E7</span> =&gt; .LVT,</span>
<span class="line" id="L793"> <span class="tok-number">0xD4E9</span>...<span class="tok-number">0xD503</span> =&gt; .LVT,</span>
<span class="line" id="L794"> <span class="tok-number">0xD505</span>...<span class="tok-number">0xD51F</span> =&gt; .LVT,</span>
<span class="line" id="L795"> <span class="tok-number">0xD521</span>...<span class="tok-number">0xD53B</span> =&gt; .LVT,</span>
<span class="line" id="L796"> <span class="tok-number">0xD53D</span>...<span class="tok-number">0xD557</span> =&gt; .LVT,</span>
<span class="line" id="L797"> <span class="tok-number">0xD559</span>...<span class="tok-number">0xD573</span> =&gt; .LVT,</span>
<span class="line" id="L798"> <span class="tok-number">0xD575</span>...<span class="tok-number">0xD58F</span> =&gt; .LVT,</span>
<span class="line" id="L799"> <span class="tok-number">0xD591</span>...<span class="tok-number">0xD5AB</span> =&gt; .LVT,</span>
<span class="line" id="L800"> <span class="tok-number">0xD5AD</span>...<span class="tok-number">0xD5C7</span> =&gt; .LVT,</span>
<span class="line" id="L801"> <span class="tok-number">0xD5C9</span>...<span class="tok-number">0xD5E3</span> =&gt; .LVT,</span>
<span class="line" id="L802"> <span class="tok-number">0xD5E5</span>...<span class="tok-number">0xD5FF</span> =&gt; .LVT,</span>
<span class="line" id="L803"> <span class="tok-number">0xD601</span>...<span class="tok-number">0xD61B</span> =&gt; .LVT,</span>
<span class="line" id="L804"> <span class="tok-number">0xD61D</span>...<span class="tok-number">0xD637</span> =&gt; .LVT,</span>
<span class="line" id="L805"> <span class="tok-number">0xD639</span>...<span class="tok-number">0xD653</span> =&gt; .LVT,</span>
<span class="line" id="L806"> <span class="tok-number">0xD655</span>...<span class="tok-number">0xD66F</span> =&gt; .LVT,</span>
<span class="line" id="L807"> <span class="tok-number">0xD671</span>...<span class="tok-number">0xD68B</span> =&gt; .LVT,</span>
<span class="line" id="L808"> <span class="tok-number">0xD68D</span>...<span class="tok-number">0xD6A7</span> =&gt; .LVT,</span>
<span class="line" id="L809"> <span class="tok-number">0xD6A9</span>...<span class="tok-number">0xD6C3</span> =&gt; .LVT,</span>
<span class="line" id="L810"> <span class="tok-number">0xD6C5</span>...<span class="tok-number">0xD6DF</span> =&gt; .LVT,</span>
<span class="line" id="L811"> <span class="tok-number">0xD6E1</span>...<span class="tok-number">0xD6FB</span> =&gt; .LVT,</span>
<span class="line" id="L812"> <span class="tok-number">0xD6FD</span>...<span class="tok-number">0xD717</span> =&gt; .LVT,</span>
<span class="line" id="L813"> <span class="tok-number">0xD719</span>...<span class="tok-number">0xD733</span> =&gt; .LVT,</span>
<span class="line" id="L814"> <span class="tok-number">0xD735</span>...<span class="tok-number">0xD74F</span> =&gt; .LVT,</span>
<span class="line" id="L815"> <span class="tok-number">0xD751</span>...<span class="tok-number">0xD76B</span> =&gt; .LVT,</span>
<span class="line" id="L816"> <span class="tok-number">0xD76D</span>...<span class="tok-number">0xD787</span> =&gt; .LVT,</span>
<span class="line" id="L817"> <span class="tok-number">0xD789</span>...<span class="tok-number">0xD7A3</span> =&gt; .LVT,</span>
<span class="line" id="L818"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">null</span>,</span>
<span class="line" id="L819"> };</span>
<span class="line" id="L820">}</span>
<span class="line" id="L821"></span>
</code></pre></body>
</html>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,331 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>category/letter.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `letter` provides functions for hte Letter (L) Unicode category.</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> case_fold_map = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/case_folding.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> props = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_core_properties.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> cats = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_general_category.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> lower_map = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/lower_map.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">const</span> title_map = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/title_map.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> upper_map = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/upper_map.zig&quot;</span>);</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-comment">/// `isCased` detects letters that can be either upper, lower, or title cased.</span></span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isCased</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L14"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L15"> <span class="tok-kw">if</span> ((<span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) <span class="tok-kw">or</span> (<span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L16"> <span class="tok-kw">return</span> props.isCased(cp);</span>
<span class="line" id="L17">}</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"><span class="tok-comment">/// `isLetter` covers all letters in Unicode, not just ASCII.</span></span>
<span class="line" id="L20"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isLetter</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L21"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L22"> <span class="tok-kw">if</span> ((<span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) <span class="tok-kw">or</span> (<span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L23"></span>
<span class="line" id="L24"> <span class="tok-kw">return</span> cats.isLowercaseLetter(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L25"> cats.isUppercaseLetter(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L26"> cats.isTitlecaseLetter(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L27"> cats.isModifierLetter(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L28"> cats.isOtherLetter(cp);</span>
<span class="line" id="L29">}</span>
<span class="line" id="L30"></span>
<span class="line" id="L31"><span class="tok-comment">/// `isAscii` detects ASCII only letters.</span></span>
<span class="line" id="L32"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiLetter</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L33"> <span class="tok-kw">return</span> (<span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) <span class="tok-kw">or</span> (<span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>);</span>
<span class="line" id="L34">}</span>
<span class="line" id="L35"></span>
<span class="line" id="L36"><span class="tok-comment">/// `isLower` detects code points that are lowercase.</span></span>
<span class="line" id="L37"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isLower</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L38"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L39"> <span class="tok-kw">if</span> (<span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L40"> <span class="tok-kw">return</span> props.isLowercase(cp);</span>
<span class="line" id="L41">}</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"><span class="tok-comment">/// `isAsciiLower` detects ASCII only lowercase letters.</span></span>
<span class="line" id="L44"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiLower</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L45"> <span class="tok-kw">return</span> <span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>;</span>
<span class="line" id="L46">}</span>
<span class="line" id="L47"></span>
<span class="line" id="L48"><span class="tok-comment">/// `isTitle` detects code points in titlecase.</span></span>
<span class="line" id="L49"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isTitle</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L50"> <span class="tok-kw">return</span> cats.isTitlecaseLetter(cp);</span>
<span class="line" id="L51">}</span>
<span class="line" id="L52"></span>
<span class="line" id="L53"><span class="tok-comment">/// `isUpper` detects code points in uppercase.</span></span>
<span class="line" id="L54"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isUpper</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L55"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L56"> <span class="tok-kw">if</span> ((<span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L57"> <span class="tok-kw">return</span> props.isUppercase(cp);</span>
<span class="line" id="L58">}</span>
<span class="line" id="L59"></span>
<span class="line" id="L60"><span class="tok-comment">/// `isAsciiUpper` detects ASCII only uppercase letters.</span></span>
<span class="line" id="L61"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiUpper</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L62"> <span class="tok-kw">return</span> <span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>;</span>
<span class="line" id="L63">}</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"><span class="tok-comment">/// `toLower` returns the lowercase mapping for the given code point, or itself if none found.</span></span>
<span class="line" id="L66"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toLower</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L67"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L68"> <span class="tok-kw">if</span> (<span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) <span class="tok-kw">return</span> cp ^ <span class="tok-number">32</span>;</span>
<span class="line" id="L69"> <span class="tok-kw">return</span> lower_map.toLower(cp);</span>
<span class="line" id="L70">}</span>
<span class="line" id="L71"></span>
<span class="line" id="L72"><span class="tok-comment">/// `toAsciiLower` converts an ASCII letter to lowercase.</span></span>
<span class="line" id="L73"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toAsciiLower</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L74"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (<span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) cp ^ <span class="tok-number">32</span> <span class="tok-kw">else</span> cp;</span>
<span class="line" id="L75">}</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"><span class="tok-comment">/// `toTitle` returns the titlecase mapping for the given code point, or itself if none found.</span></span>
<span class="line" id="L78"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toTitle</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L79"> <span class="tok-kw">return</span> title_map.toTitle(cp);</span>
<span class="line" id="L80">}</span>
<span class="line" id="L81"></span>
<span class="line" id="L82"><span class="tok-comment">/// `toUpper` returns the uppercase mapping for the given code point, or itself if none found.</span></span>
<span class="line" id="L83"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toUpper</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L84"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L85"> <span class="tok-kw">if</span> (<span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>) <span class="tok-kw">return</span> cp ^ <span class="tok-number">32</span>;</span>
<span class="line" id="L86"> <span class="tok-kw">return</span> upper_map.toUpper(cp);</span>
<span class="line" id="L87">}</span>
<span class="line" id="L88"></span>
<span class="line" id="L89"><span class="tok-comment">/// `toAsciiUpper` converts an ASCII letter to uppercase.</span></span>
<span class="line" id="L90"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toAsciiUpper</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L91"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (<span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>) cp ^ <span class="tok-number">32</span> <span class="tok-kw">else</span> cp;</span>
<span class="line" id="L92">}</span>
<span class="line" id="L93"></span>
<span class="line" id="L94"><span class="tok-comment">/// `toCaseFold` will convert a code point into its case folded equivalent. Note that this can result</span></span>
<span class="line" id="L95"><span class="tok-comment">/// in a mapping to more than one code point, known as the full case fold. The returned array has 3</span></span>
<span class="line" id="L96"><span class="tok-comment">/// elements and the code points span until the first element equal to 0 or the end, whichever is first.</span></span>
<span class="line" id="L97"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toCaseFold</span>(cp: <span class="tok-type">u21</span>) [<span class="tok-number">3</span>]<span class="tok-type">u21</span> {</span>
<span class="line" id="L98"> <span class="tok-kw">return</span> case_fold_map.toCaseFold(cp);</span>
<span class="line" id="L99">}</span>
<span class="line" id="L100"></span>
<span class="line" id="L101"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter&quot;</span> {</span>
<span class="line" id="L102"> <span class="tok-kw">const</span> z = <span class="tok-str">'z'</span>;</span>
<span class="line" id="L103"> <span class="tok-kw">try</span> std.testing.expect(isLetter(z));</span>
<span class="line" id="L104"> <span class="tok-kw">try</span> std.testing.expect(!isUpper(z));</span>
<span class="line" id="L105"> <span class="tok-kw">const</span> uz = toUpper(z);</span>
<span class="line" id="L106"> <span class="tok-kw">try</span> std.testing.expect(isUpper(uz));</span>
<span class="line" id="L107"> <span class="tok-kw">try</span> std.testing.expectEqual(uz, <span class="tok-str">'Z'</span>);</span>
<span class="line" id="L108">}</span>
<span class="line" id="L109"></span>
<span class="line" id="L110"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter isCased&quot;</span> {</span>
<span class="line" id="L111"> <span class="tok-kw">try</span> std.testing.expect(isCased(<span class="tok-str">'a'</span>));</span>
<span class="line" id="L112"> <span class="tok-kw">try</span> std.testing.expect(isCased(<span class="tok-str">'A'</span>));</span>
<span class="line" id="L113"> <span class="tok-kw">try</span> std.testing.expect(!isCased(<span class="tok-str">'1'</span>));</span>
<span class="line" id="L114">}</span>
<span class="line" id="L115"></span>
<span class="line" id="L116"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter isLower&quot;</span> {</span>
<span class="line" id="L117"> <span class="tok-kw">try</span> std.testing.expect(isLower(<span class="tok-str">'a'</span>));</span>
<span class="line" id="L118"> <span class="tok-kw">try</span> std.testing.expect(isAsciiLower(<span class="tok-str">'a'</span>));</span>
<span class="line" id="L119"> <span class="tok-kw">try</span> std.testing.expect(isLower(<span class="tok-str">'é'</span>));</span>
<span class="line" id="L120"> <span class="tok-kw">try</span> std.testing.expect(isLower(<span class="tok-str">'i'</span>));</span>
<span class="line" id="L121"> <span class="tok-kw">try</span> std.testing.expect(!isLower(<span class="tok-str">'A'</span>));</span>
<span class="line" id="L122"> <span class="tok-kw">try</span> std.testing.expect(!isLower(<span class="tok-str">'É'</span>));</span>
<span class="line" id="L123"> <span class="tok-kw">try</span> std.testing.expect(!isLower(<span class="tok-str">'İ'</span>));</span>
<span class="line" id="L124">}</span>
<span class="line" id="L125"></span>
<span class="line" id="L126"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter toCaseFold&quot;</span> {</span>
<span class="line" id="L127"> <span class="tok-kw">var</span> result = toCaseFold(<span class="tok-str">'A'</span>);</span>
<span class="line" id="L128"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'a'</span>, <span class="tok-number">0</span>, <span class="tok-number">0</span> }, &amp;result);</span>
<span class="line" id="L129"></span>
<span class="line" id="L130"> result = toCaseFold(<span class="tok-str">'a'</span>);</span>
<span class="line" id="L131"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'a'</span>, <span class="tok-number">0</span>, <span class="tok-number">0</span> }, &amp;result);</span>
<span class="line" id="L132"></span>
<span class="line" id="L133"> result = toCaseFold(<span class="tok-str">'1'</span>);</span>
<span class="line" id="L134"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'1'</span>, <span class="tok-number">0</span>, <span class="tok-number">0</span> }, &amp;result);</span>
<span class="line" id="L135"></span>
<span class="line" id="L136"> result = toCaseFold(<span class="tok-str">'\u{00DF}'</span>);</span>
<span class="line" id="L137"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-number">0x0073</span>, <span class="tok-number">0x0073</span>, <span class="tok-number">0</span> }, &amp;result);</span>
<span class="line" id="L138"></span>
<span class="line" id="L139"> result = toCaseFold(<span class="tok-str">'\u{0390}'</span>);</span>
<span class="line" id="L140"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-number">0x03B9</span>, <span class="tok-number">0x0308</span>, <span class="tok-number">0x0301</span> }, &amp;result);</span>
<span class="line" id="L141">}</span>
<span class="line" id="L142"></span>
<span class="line" id="L143"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter toLower&quot;</span> {</span>
<span class="line" id="L144"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-str">'a'</span>), <span class="tok-str">'a'</span>);</span>
<span class="line" id="L145"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-str">'A'</span>), <span class="tok-str">'a'</span>);</span>
<span class="line" id="L146"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-str">'İ'</span>), <span class="tok-str">'i'</span>);</span>
<span class="line" id="L147"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-str">'É'</span>), <span class="tok-str">'é'</span>);</span>
<span class="line" id="L148"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-number">0x80</span>), <span class="tok-number">0x80</span>);</span>
<span class="line" id="L149"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-number">0x80</span>), <span class="tok-number">0x80</span>);</span>
<span class="line" id="L150"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-str">'Å'</span>), <span class="tok-str">'å'</span>);</span>
<span class="line" id="L151"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-str">'å'</span>), <span class="tok-str">'å'</span>);</span>
<span class="line" id="L152"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-str">'\u{212A}'</span>), <span class="tok-str">'k'</span>);</span>
<span class="line" id="L153"> <span class="tok-kw">try</span> std.testing.expectEqual(toLower(<span class="tok-str">'1'</span>), <span class="tok-str">'1'</span>);</span>
<span class="line" id="L154">}</span>
<span class="line" id="L155"></span>
<span class="line" id="L156"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter isUpper&quot;</span> {</span>
<span class="line" id="L157"> <span class="tok-kw">try</span> std.testing.expect(!isUpper(<span class="tok-str">'a'</span>));</span>
<span class="line" id="L158"> <span class="tok-kw">try</span> std.testing.expect(!isAsciiUpper(<span class="tok-str">'a'</span>));</span>
<span class="line" id="L159"> <span class="tok-kw">try</span> std.testing.expect(!isUpper(<span class="tok-str">'é'</span>));</span>
<span class="line" id="L160"> <span class="tok-kw">try</span> std.testing.expect(!isUpper(<span class="tok-str">'i'</span>));</span>
<span class="line" id="L161"> <span class="tok-kw">try</span> std.testing.expect(isUpper(<span class="tok-str">'A'</span>));</span>
<span class="line" id="L162"> <span class="tok-kw">try</span> std.testing.expect(isUpper(<span class="tok-str">'É'</span>));</span>
<span class="line" id="L163"> <span class="tok-kw">try</span> std.testing.expect(isUpper(<span class="tok-str">'İ'</span>));</span>
<span class="line" id="L164">}</span>
<span class="line" id="L165"></span>
<span class="line" id="L166"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter toUpper&quot;</span> {</span>
<span class="line" id="L167"> <span class="tok-kw">try</span> std.testing.expectEqual(toUpper(<span class="tok-str">'a'</span>), <span class="tok-str">'A'</span>);</span>
<span class="line" id="L168"> <span class="tok-kw">try</span> std.testing.expectEqual(toUpper(<span class="tok-str">'A'</span>), <span class="tok-str">'A'</span>);</span>
<span class="line" id="L169"> <span class="tok-kw">try</span> std.testing.expectEqual(toUpper(<span class="tok-str">'i'</span>), <span class="tok-str">'I'</span>);</span>
<span class="line" id="L170"> <span class="tok-kw">try</span> std.testing.expectEqual(toUpper(<span class="tok-str">'é'</span>), <span class="tok-str">'É'</span>);</span>
<span class="line" id="L171"> <span class="tok-kw">try</span> std.testing.expectEqual(toUpper(<span class="tok-number">0x80</span>), <span class="tok-number">0x80</span>);</span>
<span class="line" id="L172"> <span class="tok-kw">try</span> std.testing.expectEqual(toUpper(<span class="tok-str">'Å'</span>), <span class="tok-str">'Å'</span>);</span>
<span class="line" id="L173"> <span class="tok-kw">try</span> std.testing.expectEqual(toUpper(<span class="tok-str">'å'</span>), <span class="tok-str">'Å'</span>);</span>
<span class="line" id="L174"> <span class="tok-kw">try</span> std.testing.expectEqual(toUpper(<span class="tok-str">'1'</span>), <span class="tok-str">'1'</span>);</span>
<span class="line" id="L175">}</span>
<span class="line" id="L176"></span>
<span class="line" id="L177"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter isTitle&quot;</span> {</span>
<span class="line" id="L178"> <span class="tok-kw">try</span> std.testing.expect(!isTitle(<span class="tok-str">'a'</span>));</span>
<span class="line" id="L179"> <span class="tok-kw">try</span> std.testing.expect(!isTitle(<span class="tok-str">'é'</span>));</span>
<span class="line" id="L180"> <span class="tok-kw">try</span> std.testing.expect(!isTitle(<span class="tok-str">'i'</span>));</span>
<span class="line" id="L181"> <span class="tok-kw">try</span> std.testing.expect(isTitle(<span class="tok-str">'\u{1FBC}'</span>));</span>
<span class="line" id="L182"> <span class="tok-kw">try</span> std.testing.expect(isTitle(<span class="tok-str">'\u{1FCC}'</span>));</span>
<span class="line" id="L183"> <span class="tok-kw">try</span> std.testing.expect(isTitle(<span class="tok-str">'Lj'</span>));</span>
<span class="line" id="L184">}</span>
<span class="line" id="L185"></span>
<span class="line" id="L186"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter toTitle&quot;</span> {</span>
<span class="line" id="L187"> <span class="tok-kw">try</span> std.testing.expectEqual(toTitle(<span class="tok-str">'a'</span>), <span class="tok-str">'A'</span>);</span>
<span class="line" id="L188"> <span class="tok-kw">try</span> std.testing.expectEqual(toTitle(<span class="tok-str">'A'</span>), <span class="tok-str">'A'</span>);</span>
<span class="line" id="L189"> <span class="tok-kw">try</span> std.testing.expectEqual(toTitle(<span class="tok-str">'i'</span>), <span class="tok-str">'I'</span>);</span>
<span class="line" id="L190"> <span class="tok-kw">try</span> std.testing.expectEqual(toTitle(<span class="tok-str">'é'</span>), <span class="tok-str">'É'</span>);</span>
<span class="line" id="L191"> <span class="tok-kw">try</span> std.testing.expectEqual(toTitle(<span class="tok-str">'1'</span>), <span class="tok-str">'1'</span>);</span>
<span class="line" id="L192">}</span>
<span class="line" id="L193"></span>
<span class="line" id="L194"><span class="tok-kw">test</span> <span class="tok-str">&quot;letter isLetter&quot;</span> {</span>
<span class="line" id="L195"> <span class="tok-kw">var</span> cp: <span class="tok-type">u21</span> = <span class="tok-str">'a'</span>;</span>
<span class="line" id="L196"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'z'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L197"> <span class="tok-kw">try</span> std.testing.expect(isLetter(cp));</span>
<span class="line" id="L198"> }</span>
<span class="line" id="L199"></span>
<span class="line" id="L200"> cp = <span class="tok-str">'A'</span>;</span>
<span class="line" id="L201"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'Z'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L202"> <span class="tok-kw">try</span> std.testing.expect(isLetter(cp));</span>
<span class="line" id="L203"> }</span>
<span class="line" id="L204"></span>
<span class="line" id="L205"> <span class="tok-kw">try</span> std.testing.expect(isLetter(<span class="tok-str">'É'</span>));</span>
<span class="line" id="L206"> <span class="tok-kw">try</span> std.testing.expect(isLetter(<span class="tok-str">'\u{2CEB3}'</span>));</span>
<span class="line" id="L207"> <span class="tok-kw">try</span> std.testing.expect(!isLetter(<span class="tok-str">'\u{0003}'</span>));</span>
<span class="line" id="L208">}</span>
<span class="line" id="L209"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,135 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>category/mark.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `mark` contains a function to detect Unicode marks, category (M).</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> cats = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_general_category.zig&quot;</span>);</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-comment">/// `isMark` detects any type of Unicode mark (M) code point.</span></span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isMark</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L9"> <span class="tok-kw">return</span> cats.isSpacingMark(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L10"> cats.isNonspacingMark(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L11"> cats.isEnclosingMark(cp);</span>
<span class="line" id="L12">}</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">test</span> <span class="tok-str">&quot;mark isMark&quot;</span> {</span>
<span class="line" id="L15"> <span class="tok-kw">try</span> std.testing.expect(isMark(<span class="tok-str">'\u{20E4}'</span>));</span>
<span class="line" id="L16"> <span class="tok-kw">try</span> std.testing.expect(isMark(<span class="tok-number">0x0301</span>));</span>
<span class="line" id="L17"> <span class="tok-kw">try</span> std.testing.expect(!isMark(<span class="tok-str">'='</span>));</span>
<span class="line" id="L18">}</span>
<span class="line" id="L19"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,202 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>category/number.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `number` contains functions related to Unicode numbers; category (N).</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> cats = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_general_category.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> numeric = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_numeric_type.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> props = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/prop_list.zig&quot;</span>);</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-comment">/// `isDecimal` detects all Unicode decimal numbers.</span></span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isDecimal</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L11"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L12"> <span class="tok-kw">if</span> (<span class="tok-str">'0'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L13"> <span class="tok-kw">return</span> numeric.isDecimal(cp);</span>
<span class="line" id="L14">}</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-comment">/// `isDigit` detects variantes of decimal digits.</span></span>
<span class="line" id="L17"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L18"> <span class="tok-kw">return</span> numeric.isDigit(cp);</span>
<span class="line" id="L19">}</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-comment">/// `isAsciiDigit` detects ASCII only digits.</span></span>
<span class="line" id="L22"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L23"> <span class="tok-kw">return</span> <span class="tok-str">'0'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>;</span>
<span class="line" id="L24">}</span>
<span class="line" id="L25"></span>
<span class="line" id="L26"><span class="tok-comment">/// `isHex` detects the 16 ASCII characters 0-9 A-F, and a-f.</span></span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isHexDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L28"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L29"> <span class="tok-kw">if</span> ((<span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'f'</span>) <span class="tok-kw">or</span> (<span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'F'</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-str">'0'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L30"> <span class="tok-kw">return</span> props.isHexDigit(cp);</span>
<span class="line" id="L31">}</span>
<span class="line" id="L32"></span>
<span class="line" id="L33"><span class="tok-comment">/// `isAsciiHexDigit` detects ASCII only hexadecimal digits.</span></span>
<span class="line" id="L34"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiHexDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L35"> <span class="tok-kw">return</span> (<span class="tok-str">'a'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'f'</span>) <span class="tok-kw">or</span> (<span class="tok-str">'A'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'F'</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-str">'0'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>);</span>
<span class="line" id="L36">}</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"><span class="tok-comment">/// `isNumber` covers all Unicode numbers, not just ASII.</span></span>
<span class="line" id="L39"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isNumber</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L40"> <span class="tok-comment">// ASCII optimization.</span>
</span>
<span class="line" id="L41"> <span class="tok-kw">if</span> (<span class="tok-str">'0'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L42"> <span class="tok-kw">return</span> isDecimal(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L43"> isDigit(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L44"> numeric.isNumeric(cp);</span>
<span class="line" id="L45">}</span>
<span class="line" id="L46"></span>
<span class="line" id="L47"><span class="tok-comment">/// isAsciiNumber detects ASCII only numbers.</span></span>
<span class="line" id="L48"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiNumber</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L49"> <span class="tok-kw">return</span> <span class="tok-str">'0'</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>;</span>
<span class="line" id="L50">}</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"><span class="tok-kw">test</span> <span class="tok-str">&quot;number isDecimal&quot;</span> {</span>
<span class="line" id="L53"> <span class="tok-kw">var</span> cp: <span class="tok-type">u21</span> = <span class="tok-str">'0'</span>;</span>
<span class="line" id="L54"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'9'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L55"> <span class="tok-kw">try</span> std.testing.expect(isDecimal(cp));</span>
<span class="line" id="L56"> <span class="tok-kw">try</span> std.testing.expect(isAsciiDigit(cp));</span>
<span class="line" id="L57"> <span class="tok-kw">try</span> std.testing.expect(isAsciiNumber(cp));</span>
<span class="line" id="L58"> }</span>
<span class="line" id="L59"></span>
<span class="line" id="L60"> <span class="tok-kw">try</span> std.testing.expect(!isDecimal(<span class="tok-str">'\u{0003}'</span>));</span>
<span class="line" id="L61"> <span class="tok-kw">try</span> std.testing.expect(!isDecimal(<span class="tok-str">'A'</span>));</span>
<span class="line" id="L62">}</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"><span class="tok-kw">test</span> <span class="tok-str">&quot;number isHexDigit&quot;</span> {</span>
<span class="line" id="L65"> <span class="tok-kw">var</span> cp: <span class="tok-type">u21</span> = <span class="tok-str">'0'</span>;</span>
<span class="line" id="L66"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'9'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L67"> <span class="tok-kw">try</span> std.testing.expect(isHexDigit(cp));</span>
<span class="line" id="L68"> }</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-kw">try</span> std.testing.expect(!isHexDigit(<span class="tok-str">'\u{0003}'</span>));</span>
<span class="line" id="L71"> <span class="tok-kw">try</span> std.testing.expect(!isHexDigit(<span class="tok-str">'Z'</span>));</span>
<span class="line" id="L72">}</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"><span class="tok-kw">test</span> <span class="tok-str">&quot;number isNumber&quot;</span> {</span>
<span class="line" id="L75"> <span class="tok-kw">var</span> cp: <span class="tok-type">u21</span> = <span class="tok-str">'0'</span>;</span>
<span class="line" id="L76"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'9'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L77"> <span class="tok-kw">try</span> std.testing.expect(isNumber(cp));</span>
<span class="line" id="L78"> }</span>
<span class="line" id="L79"></span>
<span class="line" id="L80"> <span class="tok-kw">try</span> std.testing.expect(!isNumber(<span class="tok-str">'\u{0003}'</span>));</span>
<span class="line" id="L81"> <span class="tok-kw">try</span> std.testing.expect(!isNumber(<span class="tok-str">'A'</span>));</span>
<span class="line" id="L82">}</span>
<span class="line" id="L83"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,163 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>category/punct.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `punct` containes functions related to Unicode punctuation code points; category (P).</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> cats = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_general_category.zig&quot;</span>);</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-comment">/// `isPunct` detects punctuation characters. Note some punctuation maybe considered symbols by Unicode.</span></span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isPunct</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L9"> <span class="tok-kw">return</span> cats.isInitialPunctuation(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L10"> cats.isFinalPunctuation(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L11"> cats.isOpenPunctuation(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L12"> cats.isClosePunctuation(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L13"> cats.isConnectorPunctuation(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L14"> cats.isDashPunctuation(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L15"> cats.isOtherPunctuation(cp);</span>
<span class="line" id="L16">}</span>
<span class="line" id="L17"></span>
<span class="line" id="L18"><span class="tok-kw">test</span> <span class="tok-str">&quot;punct isPunct&quot;</span> {</span>
<span class="line" id="L19"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'!'</span>));</span>
<span class="line" id="L20"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'?'</span>));</span>
<span class="line" id="L21"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">','</span>));</span>
<span class="line" id="L22"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'.'</span>));</span>
<span class="line" id="L23"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">':'</span>));</span>
<span class="line" id="L24"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">';'</span>));</span>
<span class="line" id="L25"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'\''</span>));</span>
<span class="line" id="L26"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'&quot;'</span>));</span>
<span class="line" id="L27"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'¿'</span>));</span>
<span class="line" id="L28"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'¡'</span>));</span>
<span class="line" id="L29"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'-'</span>));</span>
<span class="line" id="L30"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'('</span>));</span>
<span class="line" id="L31"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">')'</span>));</span>
<span class="line" id="L32"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'{'</span>));</span>
<span class="line" id="L33"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'}'</span>));</span>
<span class="line" id="L34"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">''</span>));</span>
<span class="line" id="L35"> <span class="tok-comment">// Punct? in Unicode.</span>
</span>
<span class="line" id="L36"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'@'</span>));</span>
<span class="line" id="L37"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'#'</span>));</span>
<span class="line" id="L38"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'%'</span>));</span>
<span class="line" id="L39"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'&amp;'</span>));</span>
<span class="line" id="L40"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'*'</span>));</span>
<span class="line" id="L41"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'_'</span>));</span>
<span class="line" id="L42"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'/'</span>));</span>
<span class="line" id="L43"> <span class="tok-kw">try</span> std.testing.expect(isPunct(<span class="tok-str">'\\'</span>));</span>
<span class="line" id="L44"> <span class="tok-kw">try</span> std.testing.expect(!isPunct(<span class="tok-str">'\u{0003}'</span>));</span>
<span class="line" id="L45">}</span>
<span class="line" id="L46"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,639 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>collator/Collator.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> ccc_map = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_combining_class.zig&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> CodePointIterator = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../segmenter/CodePoint.zig&quot;</span>).CodePointIterator;</span>
<span class="line" id="L5"><span class="tok-kw">const</span> Normalizer = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../normalizer/Normalizer.zig&quot;</span>);</span>
<span class="line" id="L6"><span class="tok-kw">const</span> props = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/prop_list.zig&quot;</span>);</span>
<span class="line" id="L7"></span>
<span class="line" id="L8"><span class="tok-kw">const</span> Element = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L9"> l1: <span class="tok-type">u16</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L10"> l2: <span class="tok-type">u16</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L11"> l3: <span class="tok-type">u8</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L12">};</span>
<span class="line" id="L13"></span>
<span class="line" id="L14"><span class="tok-kw">const</span> Implicit = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L15"> start: <span class="tok-type">u21</span>,</span>
<span class="line" id="L16"> end: <span class="tok-type">u21</span>,</span>
<span class="line" id="L17"> base: <span class="tok-type">u16</span>,</span>
<span class="line" id="L18">};</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L21"></span>
<span class="line" id="L22">ducet: std.AutoHashMap([<span class="tok-number">3</span>]<span class="tok-type">u21</span>, [<span class="tok-number">18</span>]?Element),</span>
<span class="line" id="L23">implicits: [<span class="tok-number">4</span>]Implicit,</span>
<span class="line" id="L24">normalizer: Normalizer,</span>
<span class="line" id="L25"></span>
<span class="line" id="L26"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(allocator: std.mem.Allocator) !Self {</span>
<span class="line" id="L27"> <span class="tok-kw">var</span> self = Self{</span>
<span class="line" id="L28"> .ducet = std.AutoHashMap([<span class="tok-number">3</span>]<span class="tok-type">u21</span>, [<span class="tok-number">18</span>]?Element).init(allocator),</span>
<span class="line" id="L29"> .implicits = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L30"> .normalizer = <span class="tok-kw">try</span> Normalizer.init(allocator),</span>
<span class="line" id="L31"> };</span>
<span class="line" id="L32"> <span class="tok-kw">errdefer</span> self.deinit();</span>
<span class="line" id="L33"></span>
<span class="line" id="L34"> <span class="tok-comment">// allkeys-strip.txt file.</span>
</span>
<span class="line" id="L35"> <span class="tok-kw">const</span> ak_file = <span class="tok-builtin">@embedFile</span>(<span class="tok-str">&quot;../data/allkeys-diffs.txt.deflate&quot;</span>);</span>
<span class="line" id="L36"> <span class="tok-kw">var</span> ak_fb = std.io.fixedBufferStream(ak_file);</span>
<span class="line" id="L37"> <span class="tok-kw">var</span> ak_comp = <span class="tok-kw">try</span> std.compress.deflate.decompressor(allocator, ak_fb.reader(), <span class="tok-null">null</span>);</span>
<span class="line" id="L38"> <span class="tok-kw">defer</span> ak_comp.deinit();</span>
<span class="line" id="L39"> <span class="tok-kw">var</span> ak_br = std.io.bufferedReader(ak_comp.reader());</span>
<span class="line" id="L40"> <span class="tok-kw">const</span> ak_reader = ak_br.reader();</span>
<span class="line" id="L41"></span>
<span class="line" id="L42"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4096</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L43"> <span class="tok-kw">var</span> line_num: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L44"></span>
<span class="line" id="L45"> <span class="tok-comment">// Diff state</span>
</span>
<span class="line" id="L46"> <span class="tok-kw">var</span> prev_cp: <span class="tok-type">u21</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L47"> <span class="tok-kw">var</span> cp_diff: <span class="tok-type">isize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L48"> <span class="tok-kw">var</span> prev_l1: <span class="tok-type">u16</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L49"> <span class="tok-kw">var</span> l1_diff: <span class="tok-type">isize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L50"></span>
<span class="line" id="L51"> <span class="tok-kw">while</span> (<span class="tok-kw">try</span> ak_reader.readUntilDelimiterOrEof(&amp;buf, <span class="tok-str">'\n'</span>)) |line| : (line_num += <span class="tok-number">1</span>) {</span>
<span class="line" id="L52"> <span class="tok-kw">var</span> fields = std.mem.split(<span class="tok-type">u8</span>, line, <span class="tok-str">&quot;;&quot;</span>);</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-comment">// Will the number of implicits change in a future version of Unicode?</span>
</span>
<span class="line" id="L55"> <span class="tok-kw">if</span> (line_num &lt; <span class="tok-number">4</span>) {</span>
<span class="line" id="L56"> self.implicits[line_num] = Implicit{</span>
<span class="line" id="L57"> .start = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>),</span>
<span class="line" id="L58"> .end = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>),</span>
<span class="line" id="L59"> .base = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u16</span>, fields.next().?, <span class="tok-number">16</span>),</span>
<span class="line" id="L60"> };</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L63"> }</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L66"> <span class="tok-kw">var</span> cps = [_]<span class="tok-type">u21</span>{<span class="tok-number">0</span>} ** <span class="tok-number">3</span>;</span>
<span class="line" id="L67"> <span class="tok-kw">var</span> cp_diff_strs = std.mem.split(<span class="tok-type">u8</span>, fields.next().?, <span class="tok-str">&quot; &quot;</span>);</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"> <span class="tok-kw">while</span> (cp_diff_strs.next()) |cp_diff_str| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L70"> cp_diff = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">isize</span>, cp_diff_str, <span class="tok-number">16</span>);</span>
<span class="line" id="L71"> prev_cp = <span class="tok-builtin">@intCast</span>(<span class="tok-builtin">@as</span>(<span class="tok-type">isize</span>, prev_cp) + cp_diff);</span>
<span class="line" id="L72"> cps[i] = prev_cp;</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"> i = <span class="tok-number">0</span>;</span>
<span class="line" id="L76"> <span class="tok-kw">var</span> elements = [_]?Element{<span class="tok-null">null</span>} ** <span class="tok-number">18</span>;</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"> <span class="tok-kw">while</span> (fields.next()) |element_diff_str| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L79"> <span class="tok-comment">// i.e. 3D3;-42</span>
</span>
<span class="line" id="L80"> <span class="tok-kw">if</span> (std.mem.indexOf(<span class="tok-type">u8</span>, element_diff_str, <span class="tok-str">&quot;.&quot;</span>) == <span class="tok-null">null</span>) {</span>
<span class="line" id="L81"> l1_diff = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">isize</span>, element_diff_str, <span class="tok-number">16</span>);</span>
<span class="line" id="L82"> prev_l1 = <span class="tok-builtin">@intCast</span>(<span class="tok-builtin">@as</span>(<span class="tok-type">isize</span>, prev_l1) + l1_diff);</span>
<span class="line" id="L83"></span>
<span class="line" id="L84"> elements[i] = Element{</span>
<span class="line" id="L85"> .l1 = prev_l1,</span>
<span class="line" id="L86"> .l2 = <span class="tok-number">0x20</span>,</span>
<span class="line" id="L87"> .l3 = <span class="tok-number">0x2</span>,</span>
<span class="line" id="L88"> };</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L91"> }</span>
<span class="line" id="L92"></span>
<span class="line" id="L93"> <span class="tok-kw">var</span> weight_strs = std.mem.split(<span class="tok-type">u8</span>, element_diff_str, <span class="tok-str">&quot;.&quot;</span>);</span>
<span class="line" id="L94"> l1_diff = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">isize</span>, weight_strs.next().?, <span class="tok-number">16</span>);</span>
<span class="line" id="L95"> prev_l1 = <span class="tok-builtin">@intCast</span>(<span class="tok-builtin">@as</span>(<span class="tok-type">isize</span>, prev_l1) + l1_diff);</span>
<span class="line" id="L96"> elements[i] = Element{ .l1 = prev_l1 };</span>
<span class="line" id="L97"></span>
<span class="line" id="L98"> <span class="tok-kw">var</span> j: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L99"> <span class="tok-kw">while</span> (weight_strs.next()) |weight_str| : (j += <span class="tok-number">1</span>) {</span>
<span class="line" id="L100"> <span class="tok-kw">if</span> (weight_str.len == <span class="tok-number">1</span> <span class="tok-kw">and</span> weight_str[<span class="tok-number">0</span>] == <span class="tok-str">')'</span>) {</span>
<span class="line" id="L101"> elements[i].?.l2 = <span class="tok-number">0</span>;</span>
<span class="line" id="L102"> elements[i].?.l3 = <span class="tok-number">0</span>;</span>
<span class="line" id="L103"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L104"> }</span>
<span class="line" id="L105"></span>
<span class="line" id="L106"> <span class="tok-kw">if</span> (weight_str[<span class="tok-number">0</span>] == <span class="tok-str">'@'</span>) {</span>
<span class="line" id="L107"> elements[i].?.l2 = <span class="tok-number">0x20</span>;</span>
<span class="line" id="L108"> elements[i].?.l3 = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u8</span>, weight_str[<span class="tok-number">1</span>..], <span class="tok-number">16</span>);</span>
<span class="line" id="L109"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L110"> }</span>
<span class="line" id="L111"></span>
<span class="line" id="L112"> <span class="tok-kw">switch</span> (j) {</span>
<span class="line" id="L113"> <span class="tok-number">0</span> =&gt; elements[i].?.l2 = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u16</span>, weight_str, <span class="tok-number">16</span>),</span>
<span class="line" id="L114"> <span class="tok-number">1</span> =&gt; elements[i].?.l3 = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u8</span>, weight_str, <span class="tok-number">16</span>),</span>
<span class="line" id="L115"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"> }</span>
<span class="line" id="L118"> }</span>
<span class="line" id="L119"></span>
<span class="line" id="L120"> <span class="tok-kw">try</span> self.ducet.put(cps, elements);</span>
<span class="line" id="L121"> }</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"> <span class="tok-kw">return</span> self;</span>
<span class="line" id="L124">}</span>
<span class="line" id="L125"></span>
<span class="line" id="L126"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L127"> self.ducet.deinit();</span>
<span class="line" id="L128"> self.normalizer.deinit();</span>
<span class="line" id="L129">}</span>
<span class="line" id="L130"></span>
<span class="line" id="L131"><span class="tok-kw">test</span> <span class="tok-str">&quot;init / deinit&quot;</span> {</span>
<span class="line" id="L132"> <span class="tok-kw">var</span> c = <span class="tok-kw">try</span> init(std.testing.allocator);</span>
<span class="line" id="L133"> <span class="tok-kw">defer</span> c.deinit();</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">0xfb00</span>), c.implicits[<span class="tok-number">0</span>].base);</span>
<span class="line" id="L136"> <span class="tok-comment">//try std.testing.expectEqual(@as(usize, 34193), c.ducet.count()); // full</span>
</span>
<span class="line" id="L137"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">32130</span>), c.ducet.count()); <span class="tok-comment">// NFD only</span>
</span>
<span class="line" id="L138">}</span>
<span class="line" id="L139"></span>
<span class="line" id="L140"><span class="tok-kw">fn</span> <span class="tok-fn">implicitWeight</span>(self: Self, cp: <span class="tok-type">u21</span>) [<span class="tok-number">18</span>]?Element {</span>
<span class="line" id="L141"> <span class="tok-kw">var</span> base: <span class="tok-type">u16</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L142"> <span class="tok-kw">var</span> aaaa: <span class="tok-type">u16</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L143"> <span class="tok-kw">var</span> bbbb: <span class="tok-type">u16</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L144"></span>
<span class="line" id="L145"> <span class="tok-kw">if</span> (props.isUnifiedIdeograph(cp) <span class="tok-kw">and</span> ((<span class="tok-number">0x4E00</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x9FFF</span>) <span class="tok-kw">or</span> (<span class="tok-number">0xF900</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0xFAFF</span>))) {</span>
<span class="line" id="L146"> base = <span class="tok-number">0xFB40</span>;</span>
<span class="line" id="L147"> aaaa = base + <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intCast</span>((cp &gt;&gt; <span class="tok-number">15</span>)));</span>
<span class="line" id="L148"> bbbb = <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intCast</span>((cp &amp; <span class="tok-number">0x7FFF</span>))) | <span class="tok-number">0x8000</span>;</span>
<span class="line" id="L149"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (props.isUnifiedIdeograph(cp) <span class="tok-kw">and</span> !((<span class="tok-number">0x4E00</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x9FFF</span>) <span class="tok-kw">or</span> (<span class="tok-number">0xF900</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0xFAFF</span>))) {</span>
<span class="line" id="L150"> base = <span class="tok-number">0xFB80</span>;</span>
<span class="line" id="L151"> aaaa = base + <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intCast</span>((cp &gt;&gt; <span class="tok-number">15</span>)));</span>
<span class="line" id="L152"> bbbb = <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intCast</span>((cp &amp; <span class="tok-number">0x7FFF</span>))) | <span class="tok-number">0x8000</span>;</span>
<span class="line" id="L153"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L154"> <span class="tok-kw">for</span> (self.implicits) |implicit| {</span>
<span class="line" id="L155"> <span class="tok-kw">if</span> (implicit.start &lt;= cp <span class="tok-kw">and</span> cp &lt;= implicit.end) {</span>
<span class="line" id="L156"> aaaa = implicit.base;</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"> <span class="tok-kw">if</span> (<span class="tok-number">0x18D00</span> &lt;= cp <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x18D8F</span>) {</span>
<span class="line" id="L159"> bbbb = <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@truncate</span>((cp - <span class="tok-number">17000</span>))) | <span class="tok-number">0x8000</span>;</span>
<span class="line" id="L160"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L161"> bbbb = <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intCast</span>((cp - implicit.start))) | <span class="tok-number">0x8000</span>;</span>
<span class="line" id="L162"> }</span>
<span class="line" id="L163"></span>
<span class="line" id="L164"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L165"> }</span>
<span class="line" id="L166"> }</span>
<span class="line" id="L167"></span>
<span class="line" id="L168"> <span class="tok-kw">if</span> (aaaa == <span class="tok-number">0</span>) {</span>
<span class="line" id="L169"> base = <span class="tok-number">0xFBC0</span>;</span>
<span class="line" id="L170"> aaaa = base + <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intCast</span>((cp &gt;&gt; <span class="tok-number">15</span>)));</span>
<span class="line" id="L171"> bbbb = <span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-builtin">@intCast</span>((cp &amp; <span class="tok-number">0x7FFF</span>))) | <span class="tok-number">0x8000</span>;</span>
<span class="line" id="L172"> }</span>
<span class="line" id="L173"> }</span>
<span class="line" id="L174"></span>
<span class="line" id="L175"> <span class="tok-kw">var</span> elements = [_]?Element{<span class="tok-null">null</span>} ** <span class="tok-number">18</span>;</span>
<span class="line" id="L176"> elements[<span class="tok-number">0</span>] = Element{ .l1 = aaaa, .l2 = <span class="tok-number">0x0020</span>, .l3 = <span class="tok-number">0x0002</span> };</span>
<span class="line" id="L177"> elements[<span class="tok-number">1</span>] = Element{ .l1 = bbbb, .l2 = <span class="tok-number">0x0000</span>, .l3 = <span class="tok-number">0x0000</span> };</span>
<span class="line" id="L178"></span>
<span class="line" id="L179"> <span class="tok-kw">return</span> elements;</span>
<span class="line" id="L180">}</span>
<span class="line" id="L181"></span>
<span class="line" id="L182"><span class="tok-kw">fn</span> <span class="tok-fn">getElements</span>(self: Self, allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-kw">const</span> Element {</span>
<span class="line" id="L183"> std.debug.assert(str.len &gt; <span class="tok-number">0</span>);</span>
<span class="line" id="L184"></span>
<span class="line" id="L185"> <span class="tok-kw">var</span> normalized = <span class="tok-kw">try</span> self.normalizer.nfd(allocator, str);</span>
<span class="line" id="L186"> <span class="tok-kw">defer</span> normalized.deinit();</span>
<span class="line" id="L187"></span>
<span class="line" id="L188"> <span class="tok-kw">var</span> cp_list = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u21</span>).initCapacity(allocator, normalized.slice.len);</span>
<span class="line" id="L189"> <span class="tok-kw">defer</span> cp_list.deinit();</span>
<span class="line" id="L190"> <span class="tok-kw">var</span> cp_iter = CodePointIterator{ .bytes = normalized.slice };</span>
<span class="line" id="L191"> <span class="tok-kw">while</span> (cp_iter.next()) |cp| cp_list.appendAssumeCapacity(cp.code);</span>
<span class="line" id="L192"></span>
<span class="line" id="L193"> <span class="tok-kw">var</span> all_elements = std.ArrayList(Element).init(allocator);</span>
<span class="line" id="L194"> <span class="tok-kw">defer</span> all_elements.deinit();</span>
<span class="line" id="L195"></span>
<span class="line" id="L196"> <span class="tok-kw">var</span> cp_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-kw">while</span> (cp_index &lt; cp_list.items.len) {</span>
<span class="line" id="L199"> <span class="tok-kw">var</span> S: [<span class="tok-number">3</span>]<span class="tok-type">u21</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L200"> <span class="tok-kw">var</span> s_len: <span class="tok-type">usize</span> = <span class="tok-number">3</span>;</span>
<span class="line" id="L201"> <span class="tok-kw">var</span> elements: ?[<span class="tok-number">18</span>]?Element = <span class="tok-null">null</span>;</span>
<span class="line" id="L202"></span>
<span class="line" id="L203"> <span class="tok-kw">if</span> (cp_list.items.len &gt; cp_index + <span class="tok-number">2</span>) {</span>
<span class="line" id="L204"> S[<span class="tok-number">0</span>] = cp_list.items[cp_index];</span>
<span class="line" id="L205"> S[<span class="tok-number">1</span>] = cp_list.items[cp_index + <span class="tok-number">1</span>];</span>
<span class="line" id="L206"> S[<span class="tok-number">2</span>] = cp_list.items[cp_index + <span class="tok-number">2</span>];</span>
<span class="line" id="L207"> elements = self.ducet.get(S);</span>
<span class="line" id="L208"> }</span>
<span class="line" id="L209"></span>
<span class="line" id="L210"> <span class="tok-kw">if</span> (elements == <span class="tok-null">null</span> <span class="tok-kw">and</span> cp_list.items.len &gt; cp_index + <span class="tok-number">1</span>) {</span>
<span class="line" id="L211"> S[<span class="tok-number">0</span>] = cp_list.items[cp_index];</span>
<span class="line" id="L212"> S[<span class="tok-number">1</span>] = cp_list.items[cp_index + <span class="tok-number">1</span>];</span>
<span class="line" id="L213"> S[<span class="tok-number">2</span>] = <span class="tok-number">0</span>;</span>
<span class="line" id="L214"> s_len = <span class="tok-number">2</span>;</span>
<span class="line" id="L215"> elements = self.ducet.get(S);</span>
<span class="line" id="L216"> }</span>
<span class="line" id="L217"></span>
<span class="line" id="L218"> <span class="tok-kw">if</span> (elements == <span class="tok-null">null</span>) {</span>
<span class="line" id="L219"> S[<span class="tok-number">0</span>] = cp_list.items[cp_index];</span>
<span class="line" id="L220"> S[<span class="tok-number">1</span>] = <span class="tok-number">0</span>;</span>
<span class="line" id="L221"> S[<span class="tok-number">2</span>] = <span class="tok-number">0</span>;</span>
<span class="line" id="L222"> s_len = <span class="tok-number">1</span>;</span>
<span class="line" id="L223"> elements = self.ducet.get(S);</span>
<span class="line" id="L224"> }</span>
<span class="line" id="L225"></span>
<span class="line" id="L226"> <span class="tok-kw">if</span> (elements != <span class="tok-null">null</span> <span class="tok-kw">and</span> s_len &lt; <span class="tok-number">3</span>) {</span>
<span class="line" id="L227"> <span class="tok-comment">// Handle non-starters</span>
</span>
<span class="line" id="L228"> <span class="tok-kw">var</span> prev_ccc: ?<span class="tok-type">u8</span> = <span class="tok-null">null</span>;</span>
<span class="line" id="L229"> <span class="tok-kw">const</span> tail_start = cp_index + s_len; <span class="tok-comment">// 1 past S</span>
</span>
<span class="line" id="L230"> <span class="tok-kw">var</span> tail_index = tail_start;</span>
<span class="line" id="L231"></span>
<span class="line" id="L232"> <span class="tok-comment">// Advance to last combining C.</span>
</span>
<span class="line" id="L233"> <span class="tok-kw">while</span> (tail_index &lt; cp_list.items.len) : (tail_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L234"> <span class="tok-kw">const</span> ccc = ccc_map.combiningClass(cp_list.items[tail_index]);</span>
<span class="line" id="L235"> <span class="tok-kw">if</span> (ccc == <span class="tok-number">0</span> <span class="tok-kw">or</span> (prev_ccc != <span class="tok-null">null</span> <span class="tok-kw">and</span> prev_ccc.? &gt;= ccc)) <span class="tok-kw">break</span>;</span>
<span class="line" id="L236"> prev_ccc = ccc;</span>
<span class="line" id="L237"> }</span>
<span class="line" id="L238"></span>
<span class="line" id="L239"> <span class="tok-kw">if</span> (tail_start != tail_index) { <span class="tok-comment">// We have combining characters</span>
</span>
<span class="line" id="L240"> S[s_len] = cp_list.items[tail_index - <span class="tok-number">1</span>]; <span class="tok-comment">// S + C</span>
</span>
<span class="line" id="L241"> s_len += <span class="tok-number">1</span>;</span>
<span class="line" id="L242"></span>
<span class="line" id="L243"> <span class="tok-kw">if</span> (self.ducet.get(S)) |sc_elements| {</span>
<span class="line" id="L244"> <span class="tok-comment">// S + C has an entry; Rotate C to be just after S.</span>
</span>
<span class="line" id="L245"> <span class="tok-kw">const</span> segment = cp_list.items[tail_start..tail_index];</span>
<span class="line" id="L246"> std.mem.rotate(<span class="tok-type">u21</span>, segment, segment.len - <span class="tok-number">1</span>);</span>
<span class="line" id="L247"></span>
<span class="line" id="L248"> <span class="tok-comment">// Add S + C elements to final collection.</span>
</span>
<span class="line" id="L249"> <span class="tok-kw">for</span> (sc_elements) |element_opt| {</span>
<span class="line" id="L250"> <span class="tok-kw">if</span> (element_opt) |element| {</span>
<span class="line" id="L251"> <span class="tok-kw">try</span> all_elements.append(element);</span>
<span class="line" id="L252"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L253"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L254"> }</span>
<span class="line" id="L255"> }</span>
<span class="line" id="L256"></span>
<span class="line" id="L257"> cp_index += s_len; <span class="tok-comment">// 1 past S + C</span>
</span>
<span class="line" id="L258"></span>
<span class="line" id="L259"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L260"> }</span>
<span class="line" id="L261"></span>
<span class="line" id="L262"> <span class="tok-kw">if</span> (s_len &lt; <span class="tok-number">3</span>) S[s_len] = <span class="tok-number">0</span>; <span class="tok-comment">// back up to just S</span>
</span>
<span class="line" id="L263"> s_len -= <span class="tok-number">1</span>;</span>
<span class="line" id="L264"> }</span>
<span class="line" id="L265"> }</span>
<span class="line" id="L266"></span>
<span class="line" id="L267"> <span class="tok-kw">if</span> (elements == <span class="tok-null">null</span>) {</span>
<span class="line" id="L268"> <span class="tok-comment">// Not in DUCET; derive the elements.</span>
</span>
<span class="line" id="L269"> elements = self.implicitWeight(cp_list.items[cp_index]);</span>
<span class="line" id="L270"> }</span>
<span class="line" id="L271"></span>
<span class="line" id="L272"> <span class="tok-comment">// Add elements to final collection.</span>
</span>
<span class="line" id="L273"> <span class="tok-kw">for</span> (elements.?) |element_opt| {</span>
<span class="line" id="L274"> <span class="tok-kw">if</span> (element_opt) |element| {</span>
<span class="line" id="L275"> <span class="tok-kw">try</span> all_elements.append(element);</span>
<span class="line" id="L276"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L277"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L278"> }</span>
<span class="line" id="L279"> }</span>
<span class="line" id="L280"></span>
<span class="line" id="L281"> cp_index += s_len; <span class="tok-comment">// 1 past S</span>
</span>
<span class="line" id="L282"> }</span>
<span class="line" id="L283"></span>
<span class="line" id="L284"> <span class="tok-kw">return</span> all_elements.toOwnedSlice();</span>
<span class="line" id="L285">}</span>
<span class="line" id="L286"></span>
<span class="line" id="L287"><span class="tok-kw">test</span> <span class="tok-str">&quot;getElements&quot;</span> {</span>
<span class="line" id="L288"> <span class="tok-kw">var</span> c = <span class="tok-kw">try</span> init(std.testing.allocator);</span>
<span class="line" id="L289"> <span class="tok-kw">defer</span> c.deinit();</span>
<span class="line" id="L290"></span>
<span class="line" id="L291"> <span class="tok-kw">const</span> elements_1 = <span class="tok-kw">try</span> c.getElements(std.testing.allocator, <span class="tok-str">&quot;ca\u{301}b&quot;</span>);</span>
<span class="line" id="L292"> <span class="tok-kw">defer</span> std.testing.allocator.free(elements_1);</span>
<span class="line" id="L293"></span>
<span class="line" id="L294"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">4</span>), elements_1.len);</span>
<span class="line" id="L295"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">0x20e7</span>), elements_1[<span class="tok-number">0</span>].l1);</span>
<span class="line" id="L296"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">0x20b3</span>), elements_1[<span class="tok-number">1</span>].l1);</span>
<span class="line" id="L297"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">0x0024</span>), elements_1[<span class="tok-number">2</span>].l2);</span>
<span class="line" id="L298"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">0x20cd</span>), elements_1[<span class="tok-number">3</span>].l1);</span>
<span class="line" id="L299"></span>
<span class="line" id="L300"> <span class="tok-kw">const</span> elements_2 = <span class="tok-kw">try</span> c.getElements(std.testing.allocator, <span class="tok-str">&quot;\u{0CC6}\u{0CC2}\u{0CD5}&quot;</span>);</span>
<span class="line" id="L301"> <span class="tok-kw">defer</span> std.testing.allocator.free(elements_2);</span>
<span class="line" id="L302"></span>
<span class="line" id="L303"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">1</span>), elements_2.len);</span>
<span class="line" id="L304"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">0x2D59</span>), elements_2[<span class="tok-number">0</span>].l1);</span>
<span class="line" id="L305"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">0x0020</span>), elements_2[<span class="tok-number">0</span>].l2);</span>
<span class="line" id="L306"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u16</span>, <span class="tok-number">0x0002</span>), elements_2[<span class="tok-number">0</span>].l3);</span>
<span class="line" id="L307">}</span>
<span class="line" id="L308"></span>
<span class="line" id="L309"><span class="tok-comment">/// A sort key is a slice of `u16`s that can be compared efficiently.</span></span>
<span class="line" id="L310"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">sortKey</span>(self: Self, allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-kw">const</span> <span class="tok-type">u16</span> {</span>
<span class="line" id="L311"> <span class="tok-kw">const</span> elements = <span class="tok-kw">try</span> self.getElements(allocator, str);</span>
<span class="line" id="L312"> <span class="tok-kw">defer</span> allocator.free(elements);</span>
<span class="line" id="L313"></span>
<span class="line" id="L314"> <span class="tok-kw">var</span> sort_key = std.ArrayList(<span class="tok-type">u16</span>).init(allocator);</span>
<span class="line" id="L315"> <span class="tok-kw">defer</span> sort_key.deinit();</span>
<span class="line" id="L316"></span>
<span class="line" id="L317"> <span class="tok-kw">var</span> level: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L318"> <span class="tok-kw">while</span> (level &lt; <span class="tok-number">3</span>) : (level += <span class="tok-number">1</span>) {</span>
<span class="line" id="L319"> <span class="tok-kw">if</span> (level != <span class="tok-number">0</span>) <span class="tok-kw">try</span> sort_key.append(<span class="tok-number">0</span>); <span class="tok-comment">// level separator</span>
</span>
<span class="line" id="L320"></span>
<span class="line" id="L321"> <span class="tok-kw">for</span> (elements) |element| {</span>
<span class="line" id="L322"> <span class="tok-kw">switch</span> (level) {</span>
<span class="line" id="L323"> <span class="tok-number">0</span> =&gt; <span class="tok-kw">if</span> (element.l1 != <span class="tok-number">0</span>) <span class="tok-kw">try</span> sort_key.append(element.l1),</span>
<span class="line" id="L324"> <span class="tok-number">1</span> =&gt; <span class="tok-kw">if</span> (element.l2 != <span class="tok-number">0</span>) <span class="tok-kw">try</span> sort_key.append(element.l2),</span>
<span class="line" id="L325"> <span class="tok-number">2</span> =&gt; <span class="tok-kw">if</span> (element.l3 != <span class="tok-number">0</span>) <span class="tok-kw">try</span> sort_key.append(element.l3),</span>
<span class="line" id="L326"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L327"> }</span>
<span class="line" id="L328"> }</span>
<span class="line" id="L329"> }</span>
<span class="line" id="L330"></span>
<span class="line" id="L331"> <span class="tok-kw">return</span> sort_key.toOwnedSlice();</span>
<span class="line" id="L332">}</span>
<span class="line" id="L333"></span>
<span class="line" id="L334"><span class="tok-comment">/// Orders strings `a` and `b` based only on the base characters; case and combining marks are ignored.</span></span>
<span class="line" id="L335"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">primaryOrder</span>(a: []<span class="tok-kw">const</span> <span class="tok-type">u16</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u16</span>) std.math.Order {</span>
<span class="line" id="L336"> <span class="tok-kw">return</span> <span class="tok-kw">for</span> (a, <span class="tok-number">0</span>..) |weight, i| {</span>
<span class="line" id="L337"> <span class="tok-kw">if</span> (weight == <span class="tok-number">0</span>) <span class="tok-kw">break</span> .eq; <span class="tok-comment">// End of level</span>
</span>
<span class="line" id="L338"> <span class="tok-kw">const</span> order = std.math.order(weight, b[i]);</span>
<span class="line" id="L339"> <span class="tok-kw">if</span> (order != .eq) <span class="tok-kw">break</span> order;</span>
<span class="line" id="L340"> } <span class="tok-kw">else</span> .eq;</span>
<span class="line" id="L341">}</span>
<span class="line" id="L342"></span>
<span class="line" id="L343"><span class="tok-comment">/// Orders strings `a` and `b` based on base characters and combining marks; case is ignored.</span></span>
<span class="line" id="L344"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">secondaryOrder</span>(a: []<span class="tok-kw">const</span> <span class="tok-type">u16</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u16</span>) std.math.Order {</span>
<span class="line" id="L345"> <span class="tok-kw">var</span> last_level = <span class="tok-null">false</span>;</span>
<span class="line" id="L346"></span>
<span class="line" id="L347"> <span class="tok-kw">return</span> <span class="tok-kw">for</span> (a, <span class="tok-number">0</span>..) |weight, i| {</span>
<span class="line" id="L348"> <span class="tok-kw">if</span> (weight == <span class="tok-number">0</span>) {</span>
<span class="line" id="L349"> <span class="tok-kw">if</span> (last_level) <span class="tok-kw">break</span> .eq <span class="tok-kw">else</span> last_level = <span class="tok-null">true</span>;</span>
<span class="line" id="L350"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L351"> }</span>
<span class="line" id="L352"></span>
<span class="line" id="L353"> <span class="tok-kw">const</span> order = std.math.order(weight, b[i]);</span>
<span class="line" id="L354"> <span class="tok-kw">if</span> (order != .eq) <span class="tok-kw">break</span> order;</span>
<span class="line" id="L355"> } <span class="tok-kw">else</span> .eq;</span>
<span class="line" id="L356">}</span>
<span class="line" id="L357"></span>
<span class="line" id="L358"><span class="tok-comment">/// Orders strings `a` and `b` based on base characters, combining marks, and letter case.</span></span>
<span class="line" id="L359"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">tertiaryOrder</span>(a: []<span class="tok-kw">const</span> <span class="tok-type">u16</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u16</span>) std.math.Order {</span>
<span class="line" id="L360"> <span class="tok-kw">return</span> <span class="tok-kw">for</span> (a, <span class="tok-number">0</span>..) |weight, i| {</span>
<span class="line" id="L361"> <span class="tok-kw">const</span> order = std.math.order(weight, b[i]);</span>
<span class="line" id="L362"> <span class="tok-kw">if</span> (order != .eq) <span class="tok-kw">break</span> order;</span>
<span class="line" id="L363"> } <span class="tok-kw">else</span> .eq;</span>
<span class="line" id="L364">}</span>
<span class="line" id="L365"></span>
<span class="line" id="L366"><span class="tok-kw">test</span> <span class="tok-str">&quot;key order&quot;</span> {</span>
<span class="line" id="L367"> <span class="tok-kw">var</span> c = <span class="tok-kw">try</span> init(std.testing.allocator);</span>
<span class="line" id="L368"> <span class="tok-kw">defer</span> c.deinit();</span>
<span class="line" id="L369"></span>
<span class="line" id="L370"> <span class="tok-kw">const</span> key_a = <span class="tok-kw">try</span> c.sortKey(std.testing.allocator, <span class="tok-str">&quot;cab&quot;</span>);</span>
<span class="line" id="L371"> <span class="tok-kw">defer</span> std.testing.allocator.free(key_a);</span>
<span class="line" id="L372"> <span class="tok-kw">const</span> key_b = <span class="tok-kw">try</span> c.sortKey(std.testing.allocator, <span class="tok-str">&quot;Cab&quot;</span>);</span>
<span class="line" id="L373"> <span class="tok-kw">defer</span> std.testing.allocator.free(key_b);</span>
<span class="line" id="L374"></span>
<span class="line" id="L375"> <span class="tok-kw">try</span> std.testing.expectEqual(std.math.Order.eq, primaryOrder(key_a, key_b));</span>
<span class="line" id="L376"> <span class="tok-kw">try</span> std.testing.expectEqual(std.math.Order.eq, secondaryOrder(key_a, key_b));</span>
<span class="line" id="L377"> <span class="tok-kw">try</span> std.testing.expectEqual(std.math.Order.lt, tertiaryOrder(key_a, key_b));</span>
<span class="line" id="L378">}</span>
<span class="line" id="L379"></span>
<span class="line" id="L380"><span class="tok-kw">test</span> <span class="tok-str">&quot;key order with combining&quot;</span> {</span>
<span class="line" id="L381"> <span class="tok-kw">var</span> c = <span class="tok-kw">try</span> init(std.testing.allocator);</span>
<span class="line" id="L382"> <span class="tok-kw">defer</span> c.deinit();</span>
<span class="line" id="L383"></span>
<span class="line" id="L384"> <span class="tok-kw">const</span> key_a = <span class="tok-kw">try</span> c.sortKey(std.testing.allocator, <span class="tok-str">&quot;ca\u{301}b&quot;</span>);</span>
<span class="line" id="L385"> <span class="tok-kw">defer</span> std.testing.allocator.free(key_a);</span>
<span class="line" id="L386"> <span class="tok-kw">const</span> key_b = <span class="tok-kw">try</span> c.sortKey(std.testing.allocator, <span class="tok-str">&quot;Cab&quot;</span>);</span>
<span class="line" id="L387"> <span class="tok-kw">defer</span> std.testing.allocator.free(key_b);</span>
<span class="line" id="L388"></span>
<span class="line" id="L389"> <span class="tok-kw">try</span> std.testing.expectEqual(std.math.Order.eq, primaryOrder(key_a, key_b));</span>
<span class="line" id="L390"> <span class="tok-kw">try</span> std.testing.expectEqual(std.math.Order.gt, secondaryOrder(key_a, key_b));</span>
<span class="line" id="L391"> <span class="tok-kw">try</span> std.testing.expectEqual(std.math.Order.gt, tertiaryOrder(key_a, key_b));</span>
<span class="line" id="L392">}</span>
<span class="line" id="L393"></span>
<span class="line" id="L394"><span class="tok-comment">/// An ascending sort for strings that works with `std.mem.sort`. Because the API requires this function to be</span></span>
<span class="line" id="L395"><span class="tok-comment">/// infallible, it just returns `false` on errors.</span></span>
<span class="line" id="L396"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">ascending</span>(self: Self, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L397"> <span class="tok-kw">const</span> key_a = self.sortKey(self.ducet.allocator, a) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L398"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_a);</span>
<span class="line" id="L399"> <span class="tok-kw">const</span> key_b = self.sortKey(self.ducet.allocator, b) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L400"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_b);</span>
<span class="line" id="L401"></span>
<span class="line" id="L402"> <span class="tok-kw">return</span> tertiaryOrder(key_a, key_b) == .lt;</span>
<span class="line" id="L403">}</span>
<span class="line" id="L404"></span>
<span class="line" id="L405"><span class="tok-comment">/// A descending sort for strings that works with `std.mem.sort`. Because the API requires this function to be</span></span>
<span class="line" id="L406"><span class="tok-comment">/// infallible, it just returns `false` on errors.</span></span>
<span class="line" id="L407"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">descending</span>(self: Self, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L408"> <span class="tok-kw">const</span> key_a = self.sortKey(self.ducet.allocator, a) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L409"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_a);</span>
<span class="line" id="L410"> <span class="tok-kw">const</span> key_b = self.sortKey(self.ducet.allocator, b) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L411"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_b);</span>
<span class="line" id="L412"></span>
<span class="line" id="L413"> <span class="tok-kw">return</span> tertiaryOrder(key_a, key_b) == .gt;</span>
<span class="line" id="L414">}</span>
<span class="line" id="L415"></span>
<span class="line" id="L416"><span class="tok-kw">test</span> <span class="tok-str">&quot;sort functions&quot;</span> {</span>
<span class="line" id="L417"> <span class="tok-kw">var</span> c = <span class="tok-kw">try</span> init(std.testing.allocator);</span>
<span class="line" id="L418"> <span class="tok-kw">defer</span> c.deinit();</span>
<span class="line" id="L419"></span>
<span class="line" id="L420"> <span class="tok-kw">var</span> strings = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;def&quot;</span>, <span class="tok-str">&quot;xyz&quot;</span>, <span class="tok-str">&quot;abc&quot;</span> };</span>
<span class="line" id="L421"> <span class="tok-kw">var</span> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;abc&quot;</span>, <span class="tok-str">&quot;def&quot;</span>, <span class="tok-str">&quot;xyz&quot;</span> };</span>
<span class="line" id="L422"></span>
<span class="line" id="L423"> std.mem.sort([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;strings, c, ascending);</span>
<span class="line" id="L424"> <span class="tok-kw">try</span> std.testing.expectEqualSlices([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;want, &amp;strings);</span>
<span class="line" id="L425"></span>
<span class="line" id="L426"> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;xyz&quot;</span>, <span class="tok-str">&quot;def&quot;</span>, <span class="tok-str">&quot;abc&quot;</span> };</span>
<span class="line" id="L427"> std.mem.sort([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;strings, c, descending);</span>
<span class="line" id="L428"> <span class="tok-kw">try</span> std.testing.expectEqualSlices([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;want, &amp;strings);</span>
<span class="line" id="L429">}</span>
<span class="line" id="L430"></span>
<span class="line" id="L431"><span class="tok-comment">/// A caseless ascending sort for strings that works with `std.mem.sort`. Because the API requires this function to be</span></span>
<span class="line" id="L432"><span class="tok-comment">/// infallible, it just returns `false` on errors.</span></span>
<span class="line" id="L433"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">ascendingCaseless</span>(self: Self, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L434"> <span class="tok-kw">const</span> key_a = self.sortKey(self.ducet.allocator, a) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L435"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_a);</span>
<span class="line" id="L436"> <span class="tok-kw">const</span> key_b = self.sortKey(self.ducet.allocator, b) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L437"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_b);</span>
<span class="line" id="L438"></span>
<span class="line" id="L439"> <span class="tok-kw">return</span> secondaryOrder(key_a, key_b) == .lt;</span>
<span class="line" id="L440">}</span>
<span class="line" id="L441"></span>
<span class="line" id="L442"><span class="tok-comment">/// A caseless descending sort for strings that works with `std.mem.sort`. Because the API requires this function to be</span></span>
<span class="line" id="L443"><span class="tok-comment">/// infallible, it just returns `false` on errors.</span></span>
<span class="line" id="L444"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">descendingCaseless</span>(self: Self, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L445"> <span class="tok-kw">const</span> key_a = self.sortKey(self.ducet.allocator, a) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L446"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_a);</span>
<span class="line" id="L447"> <span class="tok-kw">const</span> key_b = self.sortKey(self.ducet.allocator, b) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L448"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_b);</span>
<span class="line" id="L449"></span>
<span class="line" id="L450"> <span class="tok-kw">return</span> secondaryOrder(key_a, key_b) == .gt;</span>
<span class="line" id="L451">}</span>
<span class="line" id="L452"></span>
<span class="line" id="L453"><span class="tok-kw">test</span> <span class="tok-str">&quot;caseless sort functions&quot;</span> {</span>
<span class="line" id="L454"> <span class="tok-kw">var</span> c = <span class="tok-kw">try</span> init(std.testing.allocator);</span>
<span class="line" id="L455"> <span class="tok-kw">defer</span> c.deinit();</span>
<span class="line" id="L456"></span>
<span class="line" id="L457"> <span class="tok-kw">var</span> strings = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;def&quot;</span>, <span class="tok-str">&quot;Abc&quot;</span>, <span class="tok-str">&quot;abc&quot;</span> };</span>
<span class="line" id="L458"> <span class="tok-kw">var</span> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;Abc&quot;</span>, <span class="tok-str">&quot;abc&quot;</span>, <span class="tok-str">&quot;def&quot;</span> };</span>
<span class="line" id="L459"></span>
<span class="line" id="L460"> std.mem.sort([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;strings, c, ascendingCaseless);</span>
<span class="line" id="L461"> <span class="tok-kw">try</span> std.testing.expectEqualSlices([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;want, &amp;strings);</span>
<span class="line" id="L462"></span>
<span class="line" id="L463"> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;def&quot;</span>, <span class="tok-str">&quot;Abc&quot;</span>, <span class="tok-str">&quot;abc&quot;</span> };</span>
<span class="line" id="L464"> std.mem.sort([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;strings, c, descendingCaseless);</span>
<span class="line" id="L465"> <span class="tok-kw">try</span> std.testing.expectEqualSlices([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;want, &amp;strings);</span>
<span class="line" id="L466">}</span>
<span class="line" id="L467"></span>
<span class="line" id="L468"><span class="tok-kw">test</span> <span class="tok-str">&quot;caseless / markless sort functions&quot;</span> {</span>
<span class="line" id="L469"> <span class="tok-kw">var</span> c = <span class="tok-kw">try</span> init(std.testing.allocator);</span>
<span class="line" id="L470"> <span class="tok-kw">defer</span> c.deinit();</span>
<span class="line" id="L471"></span>
<span class="line" id="L472"> <span class="tok-kw">var</span> strings = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;ábc&quot;</span>, <span class="tok-str">&quot;Abc&quot;</span>, <span class="tok-str">&quot;abc&quot;</span> };</span>
<span class="line" id="L473"> <span class="tok-kw">const</span> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;ábc&quot;</span>, <span class="tok-str">&quot;Abc&quot;</span>, <span class="tok-str">&quot;abc&quot;</span> };</span>
<span class="line" id="L474"></span>
<span class="line" id="L475"> std.mem.sort([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;strings, c, ascendingBase);</span>
<span class="line" id="L476"> <span class="tok-kw">try</span> std.testing.expectEqualSlices([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;want, &amp;strings);</span>
<span class="line" id="L477"></span>
<span class="line" id="L478"> std.mem.sort([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;strings, c, descendingBase);</span>
<span class="line" id="L479"> <span class="tok-kw">try</span> std.testing.expectEqualSlices([]<span class="tok-kw">const</span> <span class="tok-type">u8</span>, &amp;want, &amp;strings);</span>
<span class="line" id="L480">}</span>
<span class="line" id="L481"></span>
<span class="line" id="L482"><span class="tok-comment">/// An ascending sort for strings that works with `std.mem.sort`. This ignores case and any combining marks like</span></span>
<span class="line" id="L483"><span class="tok-comment">/// accents. Because the API requires this function to be infallible, it just returns `false` on errors.</span></span>
<span class="line" id="L484"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">ascendingBase</span>(self: Self, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L485"> <span class="tok-kw">const</span> key_a = self.sortKey(self.ducet.allocator, a) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L486"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_a);</span>
<span class="line" id="L487"> <span class="tok-kw">const</span> key_b = self.sortKey(self.ducet.allocator, b) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L488"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_b);</span>
<span class="line" id="L489"></span>
<span class="line" id="L490"> <span class="tok-kw">return</span> primaryOrder(key_a, key_b) == .lt;</span>
<span class="line" id="L491">}</span>
<span class="line" id="L492"></span>
<span class="line" id="L493"><span class="tok-comment">/// A descending sort for strings that works with `std.mem.sort`. This ignores case and any combining marks like</span></span>
<span class="line" id="L494"><span class="tok-comment">/// accents. Because the API requires this function to be infallible, it just returns `false` on errors.</span></span>
<span class="line" id="L495"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">descendingBase</span>(self: Self, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L496"> <span class="tok-kw">const</span> key_a = self.sortKey(self.ducet.allocator, a) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L497"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_a);</span>
<span class="line" id="L498"> <span class="tok-kw">const</span> key_b = self.sortKey(self.ducet.allocator, b) <span class="tok-kw">catch</span> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L499"> <span class="tok-kw">defer</span> self.ducet.allocator.free(key_b);</span>
<span class="line" id="L500"></span>
<span class="line" id="L501"> <span class="tok-kw">return</span> primaryOrder(key_a, key_b) == .gt;</span>
<span class="line" id="L502">}</span>
<span class="line" id="L503"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,540 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>display_width.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `display_width` provides functions that calculate the display width of a code point or string when displayed in a</span></span>
<span class="line" id="L2"><span class="tok-comment">//! fixed-width font.</span></span>
<span class="line" id="L3"></span>
<span class="line" id="L4"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L5"><span class="tok-kw">const</span> unicode = std.unicode;</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> cats = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph.zig&quot;</span>).general_category;</span>
<span class="line" id="L8"><span class="tok-kw">const</span> eaw = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph.zig&quot;</span>).east_asian_width;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> emoji = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph.zig&quot;</span>).emoji;</span>
<span class="line" id="L10"><span class="tok-kw">const</span> gbp = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph.zig&quot;</span>).grapheme_break;</span>
<span class="line" id="L11"><span class="tok-kw">const</span> GraphemeIterator = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph.zig&quot;</span>).GraphemeIterator;</span>
<span class="line" id="L12"><span class="tok-kw">const</span> Word = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;ziglyph.zig&quot;</span>).Word;</span>
<span class="line" id="L13"><span class="tok-kw">const</span> WordIterator = Word.WordIterator;</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-kw">fn</span> <span class="tok-fn">isAsciiStr</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L16"> <span class="tok-kw">return</span> <span class="tok-kw">for</span> (str) |b| {</span>
<span class="line" id="L17"> <span class="tok-kw">if</span> (b &gt; <span class="tok-number">127</span>) <span class="tok-kw">break</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L18"> } <span class="tok-kw">else</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L19">}</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-comment">/// AmbiguousWidth determines the width of ambiguous characters according to the context. In an</span></span>
<span class="line" id="L22"><span class="tok-comment">/// East Asian context, the width of ambiguous code points should be 2 (full), and 1 (half)</span></span>
<span class="line" id="L23"><span class="tok-comment">/// in non-East Asian contexts. The most common use case is `half`.</span></span>
<span class="line" id="L24"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> AmbiguousWidth = <span class="tok-kw">enum</span>(<span class="tok-type">u2</span>) {</span>
<span class="line" id="L25"> half = <span class="tok-number">1</span>,</span>
<span class="line" id="L26"> full = <span class="tok-number">2</span>,</span>
<span class="line" id="L27">};</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"><span class="tok-comment">/// codePointWidth returns how many cells (or columns) wide `cp` should be when rendered in a</span></span>
<span class="line" id="L30"><span class="tok-comment">/// fixed-width font.</span></span>
<span class="line" id="L31"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">codePointWidth</span>(cp: <span class="tok-type">u21</span>, am_width: AmbiguousWidth) <span class="tok-type">i3</span> {</span>
<span class="line" id="L32"> <span class="tok-kw">if</span> (cp == <span class="tok-number">0x000</span> <span class="tok-kw">or</span> cp == <span class="tok-number">0x0005</span> <span class="tok-kw">or</span> cp == <span class="tok-number">0x0007</span> <span class="tok-kw">or</span> (cp &gt;= <span class="tok-number">0x000A</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x000F</span>)) {</span>
<span class="line" id="L33"> <span class="tok-comment">// Control.</span>
</span>
<span class="line" id="L34"> <span class="tok-kw">return</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L35"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (cp == <span class="tok-number">0x0008</span> <span class="tok-kw">or</span> cp == <span class="tok-number">0x007F</span>) {</span>
<span class="line" id="L36"> <span class="tok-comment">// backspace and DEL</span>
</span>
<span class="line" id="L37"> <span class="tok-kw">return</span> -<span class="tok-number">1</span>;</span>
<span class="line" id="L38"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (cp == <span class="tok-number">0x00AD</span>) {</span>
<span class="line" id="L39"> <span class="tok-comment">// soft-hyphen</span>
</span>
<span class="line" id="L40"> <span class="tok-kw">return</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L41"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (cp == <span class="tok-number">0x2E3A</span>) {</span>
<span class="line" id="L42"> <span class="tok-comment">// two-em dash</span>
</span>
<span class="line" id="L43"> <span class="tok-kw">return</span> <span class="tok-number">2</span>;</span>
<span class="line" id="L44"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (cp == <span class="tok-number">0x2E3B</span>) {</span>
<span class="line" id="L45"> <span class="tok-comment">// three-em dash</span>
</span>
<span class="line" id="L46"> <span class="tok-kw">return</span> <span class="tok-number">3</span>;</span>
<span class="line" id="L47"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (cats.isEnclosingMark(cp) <span class="tok-kw">or</span> cats.isNonspacingMark(cp)) {</span>
<span class="line" id="L48"> <span class="tok-comment">// Combining Marks.</span>
</span>
<span class="line" id="L49"> <span class="tok-kw">return</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L50"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (cats.isFormat(cp) <span class="tok-kw">and</span> (!(cp &gt;= <span class="tok-number">0x0600</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x0605</span>) <span class="tok-kw">and</span> cp != <span class="tok-number">0x061C</span> <span class="tok-kw">and</span></span>
<span class="line" id="L51"> cp != <span class="tok-number">0x06DD</span> <span class="tok-kw">and</span> cp != <span class="tok-number">0x08E2</span>))</span>
<span class="line" id="L52"> {</span>
<span class="line" id="L53"> <span class="tok-comment">// Format except Arabic.</span>
</span>
<span class="line" id="L54"> <span class="tok-kw">return</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L55"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> ((cp &gt;= <span class="tok-number">0x1160</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x11FF</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-number">0x2060</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x206F</span>) <span class="tok-kw">or</span></span>
<span class="line" id="L56"> (cp &gt;= <span class="tok-number">0xFFF0</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0xFFF8</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-number">0xE0000</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0xE0FFF</span>))</span>
<span class="line" id="L57"> {</span>
<span class="line" id="L58"> <span class="tok-comment">// Hangul syllable and ignorable.</span>
</span>
<span class="line" id="L59"> <span class="tok-kw">return</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L60"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> ((cp &gt;= <span class="tok-number">0x3400</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x4DBF</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-number">0x4E00</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x9FFF</span>) <span class="tok-kw">or</span></span>
<span class="line" id="L61"> (cp &gt;= <span class="tok-number">0xF900</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0xFAFF</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-number">0x20000</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x2FFFD</span>) <span class="tok-kw">or</span></span>
<span class="line" id="L62"> (cp &gt;= <span class="tok-number">0x30000</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-number">0x3FFFD</span>))</span>
<span class="line" id="L63"> {</span>
<span class="line" id="L64"> <span class="tok-kw">return</span> <span class="tok-number">2</span>;</span>
<span class="line" id="L65"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (eaw.isWide(cp) <span class="tok-kw">or</span> eaw.isFullwidth(cp)) {</span>
<span class="line" id="L66"> <span class="tok-kw">return</span> <span class="tok-number">2</span>;</span>
<span class="line" id="L67"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (gbp.isRegionalIndicator(cp)) {</span>
<span class="line" id="L68"> <span class="tok-kw">return</span> <span class="tok-number">2</span>;</span>
<span class="line" id="L69"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (eaw.isAmbiguous(cp)) {</span>
<span class="line" id="L70"> <span class="tok-kw">return</span> <span class="tok-builtin">@intFromEnum</span>(am_width);</span>
<span class="line" id="L71"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L72"> <span class="tok-kw">return</span> <span class="tok-number">1</span>;</span>
<span class="line" id="L73"> }</span>
<span class="line" id="L74">}</span>
<span class="line" id="L75"></span>
<span class="line" id="L76"><span class="tok-comment">/// strWidth returns how many cells (or columns) wide `str` should be when rendered in a</span></span>
<span class="line" id="L77"><span class="tok-comment">/// fixed-width font.</span></span>
<span class="line" id="L78"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">strWidth</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, am_width: AmbiguousWidth) !<span class="tok-type">usize</span> {</span>
<span class="line" id="L79"> <span class="tok-kw">var</span> total: <span class="tok-type">isize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"> <span class="tok-comment">// ASCII bytes are all width == 1.</span>
</span>
<span class="line" id="L82"> <span class="tok-kw">if</span> (isAsciiStr(str)) {</span>
<span class="line" id="L83"> <span class="tok-kw">for</span> (str) |b| {</span>
<span class="line" id="L84"> <span class="tok-comment">// Backspace and DEL</span>
</span>
<span class="line" id="L85"> <span class="tok-kw">if</span> (b == <span class="tok-number">8</span> <span class="tok-kw">or</span> b == <span class="tok-number">127</span>) {</span>
<span class="line" id="L86"> total -= <span class="tok-number">1</span>;</span>
<span class="line" id="L87"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L88"> }</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"> <span class="tok-comment">// Control</span>
</span>
<span class="line" id="L91"> <span class="tok-kw">if</span> (b &lt; <span class="tok-number">32</span>) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L92"></span>
<span class="line" id="L93"> <span class="tok-comment">// All other ASCII.</span>
</span>
<span class="line" id="L94"> total += <span class="tok-number">1</span>;</span>
<span class="line" id="L95"> }</span>
<span class="line" id="L96"></span>
<span class="line" id="L97"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (total &gt; <span class="tok-number">0</span>) <span class="tok-builtin">@intCast</span>(total) <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L98"> }</span>
<span class="line" id="L99"></span>
<span class="line" id="L100"> <span class="tok-kw">var</span> giter = GraphemeIterator.init(str);</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"> <span class="tok-kw">while</span> (giter.next()) |gc| {</span>
<span class="line" id="L103"> <span class="tok-kw">var</span> cp_iter = (<span class="tok-kw">try</span> unicode.Utf8View.init(str[gc.offset .. gc.offset + gc.len])).iterator();</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"> <span class="tok-kw">while</span> (cp_iter.nextCodepoint()) |cp| {</span>
<span class="line" id="L106"> <span class="tok-kw">var</span> w = codePointWidth(cp, am_width);</span>
<span class="line" id="L107"></span>
<span class="line" id="L108"> <span class="tok-kw">if</span> (w != <span class="tok-number">0</span>) {</span>
<span class="line" id="L109"> <span class="tok-comment">// Only adding width of first non-zero-width code point.</span>
</span>
<span class="line" id="L110"> <span class="tok-kw">if</span> (emoji.isExtendedPictographic(cp)) {</span>
<span class="line" id="L111"> <span class="tok-kw">if</span> (cp_iter.nextCodepoint()) |ncp| {</span>
<span class="line" id="L112"> <span class="tok-comment">// emoji text sequence.</span>
</span>
<span class="line" id="L113"> <span class="tok-kw">if</span> (ncp == <span class="tok-number">0xFE0E</span>) w = <span class="tok-number">1</span>;</span>
<span class="line" id="L114"> <span class="tok-kw">if</span> (ncp == <span class="tok-number">0xFE0F</span>) w = <span class="tok-number">2</span>;</span>
<span class="line" id="L115"> }</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"> total += w;</span>
<span class="line" id="L118"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L119"> }</span>
<span class="line" id="L120"> }</span>
<span class="line" id="L121"> }</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (total &gt; <span class="tok-number">0</span>) <span class="tok-builtin">@intCast</span>(total) <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L124">}</span>
<span class="line" id="L125"></span>
<span class="line" id="L126"><span class="tok-comment">/// centers `str` in a new string of width `total_width` (in display cells) using `pad` as padding.</span></span>
<span class="line" id="L127"><span class="tok-comment">/// If the length of `str` and `total_width` have different parity, the right side of `str` will</span></span>
<span class="line" id="L128"><span class="tok-comment">/// receive one additional pad. This makes sure the returned string fills the requested width.</span></span>
<span class="line" id="L129"><span class="tok-comment">/// Caller must free returned bytes.</span></span>
<span class="line" id="L130"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">center</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, total_width: <span class="tok-type">usize</span>, pad: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L131"> <span class="tok-kw">const</span> str_width = <span class="tok-kw">try</span> strWidth(str, .half);</span>
<span class="line" id="L132"> <span class="tok-kw">if</span> (str_width &gt; total_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.StrTooLong;</span>
<span class="line" id="L133"> <span class="tok-kw">if</span> (str_width == total_width) <span class="tok-kw">return</span> <span class="tok-kw">try</span> allocator.dupe(<span class="tok-type">u8</span>, str);</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"> <span class="tok-kw">const</span> pad_width = <span class="tok-kw">try</span> strWidth(pad, .half);</span>
<span class="line" id="L136"> <span class="tok-kw">if</span> (pad_width &gt; total_width <span class="tok-kw">or</span> str_width + pad_width &gt; total_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.PadTooLong;</span>
<span class="line" id="L137"></span>
<span class="line" id="L138"> <span class="tok-kw">const</span> margin_width = <span class="tok-builtin">@divFloor</span>((total_width - str_width), <span class="tok-number">2</span>);</span>
<span class="line" id="L139"> <span class="tok-kw">if</span> (pad_width &gt; margin_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.PadTooLong;</span>
<span class="line" id="L140"> <span class="tok-kw">const</span> extra_pad: <span class="tok-type">usize</span> = <span class="tok-kw">if</span> (total_width % <span class="tok-number">2</span> != str_width % <span class="tok-number">2</span>) <span class="tok-number">1</span> <span class="tok-kw">else</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L141"> <span class="tok-kw">const</span> pads = <span class="tok-builtin">@divFloor</span>(margin_width, pad_width) * <span class="tok-number">2</span> + extra_pad;</span>
<span class="line" id="L142"></span>
<span class="line" id="L143"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> allocator.alloc(<span class="tok-type">u8</span>, pads * pad.len + str.len);</span>
<span class="line" id="L144"> <span class="tok-kw">var</span> bytes_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L145"> <span class="tok-kw">var</span> pads_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L146"></span>
<span class="line" id="L147"> <span class="tok-kw">while</span> (pads_index &lt; pads / <span class="tok-number">2</span>) : (pads_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L148"> <span class="tok-builtin">@memcpy</span>(result[bytes_index..][<span class="tok-number">0</span>..pad.len], pad);</span>
<span class="line" id="L149"> bytes_index += pad.len;</span>
<span class="line" id="L150"> }</span>
<span class="line" id="L151"></span>
<span class="line" id="L152"> <span class="tok-builtin">@memcpy</span>(result[bytes_index..][<span class="tok-number">0</span>..str.len], str);</span>
<span class="line" id="L153"> bytes_index += str.len;</span>
<span class="line" id="L154"></span>
<span class="line" id="L155"> pads_index = <span class="tok-number">0</span>;</span>
<span class="line" id="L156"> <span class="tok-kw">while</span> (pads_index &lt; pads / <span class="tok-number">2</span> + extra_pad) : (pads_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L157"> <span class="tok-builtin">@memcpy</span>(result[bytes_index..][<span class="tok-number">0</span>..pad.len], pad);</span>
<span class="line" id="L158"> bytes_index += pad.len;</span>
<span class="line" id="L159"> }</span>
<span class="line" id="L160"></span>
<span class="line" id="L161"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L162">}</span>
<span class="line" id="L163"></span>
<span class="line" id="L164"><span class="tok-comment">/// padLeft returns a new string of width `total_width` (in display cells) using `pad` as padding</span></span>
<span class="line" id="L165"><span class="tok-comment">/// on the left side. Caller must free returned bytes.</span></span>
<span class="line" id="L166"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">padLeft</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, total_width: <span class="tok-type">usize</span>, pad: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L167"> <span class="tok-kw">const</span> str_width = <span class="tok-kw">try</span> strWidth(str, .half);</span>
<span class="line" id="L168"> <span class="tok-kw">if</span> (str_width &gt; total_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.StrTooLong;</span>
<span class="line" id="L169"></span>
<span class="line" id="L170"> <span class="tok-kw">const</span> pad_width = <span class="tok-kw">try</span> strWidth(pad, .half);</span>
<span class="line" id="L171"> <span class="tok-kw">if</span> (pad_width &gt; total_width <span class="tok-kw">or</span> str_width + pad_width &gt; total_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.PadTooLong;</span>
<span class="line" id="L172"></span>
<span class="line" id="L173"> <span class="tok-kw">const</span> margin_width = total_width - str_width;</span>
<span class="line" id="L174"> <span class="tok-kw">if</span> (pad_width &gt; margin_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.PadTooLong;</span>
<span class="line" id="L175"></span>
<span class="line" id="L176"> <span class="tok-kw">const</span> pads = <span class="tok-builtin">@divFloor</span>(margin_width, pad_width);</span>
<span class="line" id="L177"></span>
<span class="line" id="L178"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> allocator.alloc(<span class="tok-type">u8</span>, pads * pad.len + str.len);</span>
<span class="line" id="L179"> <span class="tok-kw">var</span> bytes_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L180"> <span class="tok-kw">var</span> pads_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L181"></span>
<span class="line" id="L182"> <span class="tok-kw">while</span> (pads_index &lt; pads) : (pads_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L183"> <span class="tok-builtin">@memcpy</span>(result[bytes_index..][<span class="tok-number">0</span>..pad.len], pad);</span>
<span class="line" id="L184"> bytes_index += pad.len;</span>
<span class="line" id="L185"> }</span>
<span class="line" id="L186"></span>
<span class="line" id="L187"> <span class="tok-builtin">@memcpy</span>(result[bytes_index..][<span class="tok-number">0</span>..str.len], str);</span>
<span class="line" id="L188"></span>
<span class="line" id="L189"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L190">}</span>
<span class="line" id="L191"></span>
<span class="line" id="L192"><span class="tok-comment">/// padRight returns a new string of width `total_width` (in display cells) using `pad` as padding</span></span>
<span class="line" id="L193"><span class="tok-comment">/// on the right side. Caller must free returned bytes.</span></span>
<span class="line" id="L194"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">padRight</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, total_width: <span class="tok-type">usize</span>, pad: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L195"> <span class="tok-kw">const</span> str_width = <span class="tok-kw">try</span> strWidth(str, .half);</span>
<span class="line" id="L196"> <span class="tok-kw">if</span> (str_width &gt; total_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.StrTooLong;</span>
<span class="line" id="L197"></span>
<span class="line" id="L198"> <span class="tok-kw">const</span> pad_width = <span class="tok-kw">try</span> strWidth(pad, .half);</span>
<span class="line" id="L199"> <span class="tok-kw">if</span> (pad_width &gt; total_width <span class="tok-kw">or</span> str_width + pad_width &gt; total_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.PadTooLong;</span>
<span class="line" id="L200"></span>
<span class="line" id="L201"> <span class="tok-kw">const</span> margin_width = total_width - str_width;</span>
<span class="line" id="L202"> <span class="tok-kw">if</span> (pad_width &gt; margin_width) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.PadTooLong;</span>
<span class="line" id="L203"></span>
<span class="line" id="L204"> <span class="tok-kw">const</span> pads = <span class="tok-builtin">@divFloor</span>(margin_width, pad_width);</span>
<span class="line" id="L205"></span>
<span class="line" id="L206"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> allocator.alloc(<span class="tok-type">u8</span>, pads * pad.len + str.len);</span>
<span class="line" id="L207"> <span class="tok-kw">var</span> bytes_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L208"> <span class="tok-kw">var</span> pads_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L209"></span>
<span class="line" id="L210"> <span class="tok-builtin">@memcpy</span>(result[bytes_index..][<span class="tok-number">0</span>..str.len], str);</span>
<span class="line" id="L211"> bytes_index += str.len;</span>
<span class="line" id="L212"></span>
<span class="line" id="L213"> <span class="tok-kw">while</span> (pads_index &lt; pads) : (pads_index += <span class="tok-number">1</span>) {</span>
<span class="line" id="L214"> <span class="tok-builtin">@memcpy</span>(result[bytes_index..][<span class="tok-number">0</span>..pad.len], pad);</span>
<span class="line" id="L215"> bytes_index += pad.len;</span>
<span class="line" id="L216"> }</span>
<span class="line" id="L217"></span>
<span class="line" id="L218"> <span class="tok-kw">return</span> result;</span>
<span class="line" id="L219">}</span>
<span class="line" id="L220"></span>
<span class="line" id="L221"><span class="tok-comment">/// Wraps a string approximately at the given number of colums per line. Threshold defines how far the last column of</span></span>
<span class="line" id="L222"><span class="tok-comment">/// the last word can be from the edge. Caller must free returned bytes.</span></span>
<span class="line" id="L223"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">wrap</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, columns: <span class="tok-type">usize</span>, threshold: <span class="tok-type">usize</span>) ![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L224"> <span class="tok-kw">var</span> iter = <span class="tok-kw">try</span> WordIterator.init(str);</span>
<span class="line" id="L225"> <span class="tok-kw">var</span> result = std.ArrayList(<span class="tok-type">u8</span>).init(allocator);</span>
<span class="line" id="L226"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L227"> <span class="tok-kw">var</span> line_width: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L228"></span>
<span class="line" id="L229"> <span class="tok-kw">while</span> (iter.next()) |word| {</span>
<span class="line" id="L230"> <span class="tok-kw">if</span> (isLineBreak(word.bytes)) {</span>
<span class="line" id="L231"> <span class="tok-kw">try</span> result.append(<span class="tok-str">' '</span>);</span>
<span class="line" id="L232"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L233"> }</span>
<span class="line" id="L234"> <span class="tok-kw">try</span> result.appendSlice(word.bytes);</span>
<span class="line" id="L235"> line_width += <span class="tok-kw">try</span> strWidth(word.bytes, .half);</span>
<span class="line" id="L236"></span>
<span class="line" id="L237"> <span class="tok-kw">if</span> (line_width &gt; columns <span class="tok-kw">or</span> columns - line_width &lt;= threshold) {</span>
<span class="line" id="L238"> <span class="tok-kw">try</span> result.append(<span class="tok-str">'\n'</span>);</span>
<span class="line" id="L239"> line_width = <span class="tok-number">0</span>;</span>
<span class="line" id="L240"> }</span>
<span class="line" id="L241"> }</span>
<span class="line" id="L242"></span>
<span class="line" id="L243"> <span class="tok-kw">return</span> result.toOwnedSlice();</span>
<span class="line" id="L244">}</span>
<span class="line" id="L245"></span>
<span class="line" id="L246"><span class="tok-kw">fn</span> <span class="tok-fn">isLineBreak</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L247"> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, str, <span class="tok-str">&quot;\r\n&quot;</span>)) {</span>
<span class="line" id="L248"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L249"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, str, <span class="tok-str">&quot;\r&quot;</span>)) {</span>
<span class="line" id="L250"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L251"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (std.mem.eql(<span class="tok-type">u8</span>, str, <span class="tok-str">&quot;\n&quot;</span>)) {</span>
<span class="line" id="L252"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L253"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L254"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L255"> }</span>
<span class="line" id="L256">}</span>
<span class="line" id="L257"></span>
<span class="line" id="L258"><span class="tok-kw">test</span> <span class="tok-str">&quot;display_width Width&quot;</span> {</span>
<span class="line" id="L259"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, -<span class="tok-number">1</span>), codePointWidth(<span class="tok-number">0x0008</span>, .half)); <span class="tok-comment">// \b</span>
</span>
<span class="line" id="L260"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x0000</span>, .half)); <span class="tok-comment">// null</span>
</span>
<span class="line" id="L261"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x0005</span>, .half)); <span class="tok-comment">// Cf</span>
</span>
<span class="line" id="L262"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x0007</span>, .half)); <span class="tok-comment">// \a BEL</span>
</span>
<span class="line" id="L263"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x000A</span>, .half)); <span class="tok-comment">// \n LF</span>
</span>
<span class="line" id="L264"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x000B</span>, .half)); <span class="tok-comment">// \v VT</span>
</span>
<span class="line" id="L265"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x000C</span>, .half)); <span class="tok-comment">// \f FF</span>
</span>
<span class="line" id="L266"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x000D</span>, .half)); <span class="tok-comment">// \r CR</span>
</span>
<span class="line" id="L267"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x000E</span>, .half)); <span class="tok-comment">// SQ</span>
</span>
<span class="line" id="L268"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x000F</span>, .half)); <span class="tok-comment">// SI</span>
</span>
<span class="line" id="L269"></span>
<span class="line" id="L270"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">0</span>), codePointWidth(<span class="tok-number">0x070F</span>, .half)); <span class="tok-comment">// Cf</span>
</span>
<span class="line" id="L271"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">1</span>), codePointWidth(<span class="tok-number">0x0603</span>, .half)); <span class="tok-comment">// Cf Arabic</span>
</span>
<span class="line" id="L272"></span>
<span class="line" id="L273"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">1</span>), codePointWidth(<span class="tok-number">0x00AD</span>, .half)); <span class="tok-comment">// soft-hyphen</span>
</span>
<span class="line" id="L274"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">2</span>), codePointWidth(<span class="tok-number">0x2E3A</span>, .half)); <span class="tok-comment">// two-em dash</span>
</span>
<span class="line" id="L275"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">3</span>), codePointWidth(<span class="tok-number">0x2E3B</span>, .half)); <span class="tok-comment">// three-em dash</span>
</span>
<span class="line" id="L276"></span>
<span class="line" id="L277"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">1</span>), codePointWidth(<span class="tok-number">0x00BD</span>, .half)); <span class="tok-comment">// ambiguous halfwidth</span>
</span>
<span class="line" id="L278"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">2</span>), codePointWidth(<span class="tok-number">0x00BD</span>, .full)); <span class="tok-comment">// ambiguous fullwidth</span>
</span>
<span class="line" id="L279"></span>
<span class="line" id="L280"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">1</span>), codePointWidth(<span class="tok-str">'é'</span>, .half));</span>
<span class="line" id="L281"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">2</span>), codePointWidth(<span class="tok-str">'😊'</span>, .half));</span>
<span class="line" id="L282"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">i8</span>, <span class="tok-number">2</span>), codePointWidth(<span class="tok-str">'统'</span>, .half));</span>
<span class="line" id="L283"></span>
<span class="line" id="L284"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">5</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;Hello\r\n&quot;</span>, .half));</span>
<span class="line" id="L285"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">1</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\u{0065}\u{0301}&quot;</span>, .half));</span>
<span class="line" id="L286"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">2</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\u{1F476}\u{1F3FF}\u{0308}\u{200D}\u{1F476}\u{1F3FF}&quot;</span>, .half));</span>
<span class="line" id="L287"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">8</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;Hello 😊&quot;</span>, .half));</span>
<span class="line" id="L288"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">8</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;Héllo 😊&quot;</span>, .half));</span>
<span class="line" id="L289"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">8</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;Héllo :)&quot;</span>, .half));</span>
<span class="line" id="L290"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">8</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;Héllo 🇪🇸&quot;</span>, .half));</span>
<span class="line" id="L291"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">2</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\u{26A1}&quot;</span>, .half)); <span class="tok-comment">// Lone emoji</span>
</span>
<span class="line" id="L292"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">1</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\u{26A1}\u{FE0E}&quot;</span>, .half)); <span class="tok-comment">// Text sequence</span>
</span>
<span class="line" id="L293"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">2</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\u{26A1}\u{FE0F}&quot;</span>, .half)); <span class="tok-comment">// Presentation sequence</span>
</span>
<span class="line" id="L294"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">1</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\u{2764}&quot;</span>, .half)); <span class="tok-comment">// Default text presentation</span>
</span>
<span class="line" id="L295"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">1</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\u{2764}\u{FE0E}&quot;</span>, .half)); <span class="tok-comment">// Default text presentation with VS15 selector</span>
</span>
<span class="line" id="L296"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">2</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\u{2764}\u{FE0F}&quot;</span>, .half)); <span class="tok-comment">// Default text presentation with VS16 selector</span>
</span>
<span class="line" id="L297"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">0</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;A\x08&quot;</span>, .half)); <span class="tok-comment">// Backspace</span>
</span>
<span class="line" id="L298"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">0</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\x7FA&quot;</span>, .half)); <span class="tok-comment">// DEL</span>
</span>
<span class="line" id="L299"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">0</span>), <span class="tok-kw">try</span> strWidth(<span class="tok-str">&quot;\x7FA\x08\x08&quot;</span>, .half)); <span class="tok-comment">// never less than o</span>
</span>
<span class="line" id="L300">}</span>
<span class="line" id="L301"></span>
<span class="line" id="L302"><span class="tok-kw">test</span> <span class="tok-str">&quot;display_width center&quot;</span> {</span>
<span class="line" id="L303"> <span class="tok-kw">var</span> allocator = std.testing.allocator;</span>
<span class="line" id="L304"></span>
<span class="line" id="L305"> <span class="tok-comment">// Input and width both have odd length</span>
</span>
<span class="line" id="L306"> <span class="tok-kw">var</span> centered = <span class="tok-kw">try</span> center(allocator, <span class="tok-str">&quot;abc&quot;</span>, <span class="tok-number">9</span>, <span class="tok-str">&quot;*&quot;</span>);</span>
<span class="line" id="L307"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;***abc***&quot;</span>, centered);</span>
<span class="line" id="L308"></span>
<span class="line" id="L309"> <span class="tok-comment">// Input and width both have even length</span>
</span>
<span class="line" id="L310"> allocator.free(centered);</span>
<span class="line" id="L311"> centered = <span class="tok-kw">try</span> center(allocator, <span class="tok-str">&quot;w😊w&quot;</span>, <span class="tok-number">10</span>, <span class="tok-str">&quot;-&quot;</span>);</span>
<span class="line" id="L312"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;---w😊w---&quot;</span>, centered);</span>
<span class="line" id="L313"></span>
<span class="line" id="L314"> <span class="tok-comment">// Input has even length, width has odd length</span>
</span>
<span class="line" id="L315"> allocator.free(centered);</span>
<span class="line" id="L316"> centered = <span class="tok-kw">try</span> center(allocator, <span class="tok-str">&quot;1234&quot;</span>, <span class="tok-number">9</span>, <span class="tok-str">&quot;-&quot;</span>);</span>
<span class="line" id="L317"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;--1234---&quot;</span>, centered);</span>
<span class="line" id="L318"></span>
<span class="line" id="L319"> <span class="tok-comment">// Input has odd length, width has even length</span>
</span>
<span class="line" id="L320"> allocator.free(centered);</span>
<span class="line" id="L321"> centered = <span class="tok-kw">try</span> center(allocator, <span class="tok-str">&quot;123&quot;</span>, <span class="tok-number">8</span>, <span class="tok-str">&quot;-&quot;</span>);</span>
<span class="line" id="L322"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;--123---&quot;</span>, centered);</span>
<span class="line" id="L323"></span>
<span class="line" id="L324"> <span class="tok-comment">// Input is the same length as the width</span>
</span>
<span class="line" id="L325"> allocator.free(centered);</span>
<span class="line" id="L326"> centered = <span class="tok-kw">try</span> center(allocator, <span class="tok-str">&quot;123&quot;</span>, <span class="tok-number">3</span>, <span class="tok-str">&quot;-&quot;</span>);</span>
<span class="line" id="L327"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;123&quot;</span>, centered);</span>
<span class="line" id="L328"></span>
<span class="line" id="L329"> <span class="tok-comment">// Input is empty</span>
</span>
<span class="line" id="L330"> allocator.free(centered);</span>
<span class="line" id="L331"> centered = <span class="tok-kw">try</span> center(allocator, <span class="tok-str">&quot;&quot;</span>, <span class="tok-number">3</span>, <span class="tok-str">&quot;-&quot;</span>);</span>
<span class="line" id="L332"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;---&quot;</span>, centered);</span>
<span class="line" id="L333"></span>
<span class="line" id="L334"> <span class="tok-comment">// Input is empty and width is zero</span>
</span>
<span class="line" id="L335"> allocator.free(centered);</span>
<span class="line" id="L336"> centered = <span class="tok-kw">try</span> center(allocator, <span class="tok-str">&quot;&quot;</span>, <span class="tok-number">0</span>, <span class="tok-str">&quot;-&quot;</span>);</span>
<span class="line" id="L337"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;&quot;</span>, centered);</span>
<span class="line" id="L338"></span>
<span class="line" id="L339"> <span class="tok-comment">// Input is longer than the width, which is an error</span>
</span>
<span class="line" id="L340"> allocator.free(centered);</span>
<span class="line" id="L341"> <span class="tok-kw">try</span> std.testing.expectError(<span class="tok-kw">error</span>.StrTooLong, center(allocator, <span class="tok-str">&quot;123&quot;</span>, <span class="tok-number">2</span>, <span class="tok-str">&quot;-&quot;</span>));</span>
<span class="line" id="L342">}</span>
<span class="line" id="L343"></span>
<span class="line" id="L344"><span class="tok-kw">test</span> <span class="tok-str">&quot;display_width padLeft&quot;</span> {</span>
<span class="line" id="L345"> <span class="tok-kw">var</span> allocator = std.testing.allocator;</span>
<span class="line" id="L346"></span>
<span class="line" id="L347"> <span class="tok-kw">var</span> right_aligned = <span class="tok-kw">try</span> padLeft(allocator, <span class="tok-str">&quot;abc&quot;</span>, <span class="tok-number">9</span>, <span class="tok-str">&quot;*&quot;</span>);</span>
<span class="line" id="L348"> <span class="tok-kw">defer</span> allocator.free(right_aligned);</span>
<span class="line" id="L349"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;******abc&quot;</span>, right_aligned);</span>
<span class="line" id="L350"></span>
<span class="line" id="L351"> allocator.free(right_aligned);</span>
<span class="line" id="L352"> right_aligned = <span class="tok-kw">try</span> padLeft(allocator, <span class="tok-str">&quot;w😊w&quot;</span>, <span class="tok-number">10</span>, <span class="tok-str">&quot;-&quot;</span>);</span>
<span class="line" id="L353"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;------w😊w&quot;</span>, right_aligned);</span>
<span class="line" id="L354">}</span>
<span class="line" id="L355"></span>
<span class="line" id="L356"><span class="tok-kw">test</span> <span class="tok-str">&quot;display_width padRight&quot;</span> {</span>
<span class="line" id="L357"> <span class="tok-kw">var</span> allocator = std.testing.allocator;</span>
<span class="line" id="L358"></span>
<span class="line" id="L359"> <span class="tok-kw">var</span> left_aligned = <span class="tok-kw">try</span> padRight(allocator, <span class="tok-str">&quot;abc&quot;</span>, <span class="tok-number">9</span>, <span class="tok-str">&quot;*&quot;</span>);</span>
<span class="line" id="L360"> <span class="tok-kw">defer</span> allocator.free(left_aligned);</span>
<span class="line" id="L361"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;abc******&quot;</span>, left_aligned);</span>
<span class="line" id="L362"></span>
<span class="line" id="L363"> allocator.free(left_aligned);</span>
<span class="line" id="L364"> left_aligned = <span class="tok-kw">try</span> padRight(allocator, <span class="tok-str">&quot;w😊w&quot;</span>, <span class="tok-number">10</span>, <span class="tok-str">&quot;-&quot;</span>);</span>
<span class="line" id="L365"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u8</span>, <span class="tok-str">&quot;w😊w------&quot;</span>, left_aligned);</span>
<span class="line" id="L366">}</span>
<span class="line" id="L367"></span>
<span class="line" id="L368"><span class="tok-kw">test</span> <span class="tok-str">&quot;display_width wrap&quot;</span> {</span>
<span class="line" id="L369"> <span class="tok-kw">var</span> allocator = std.testing.allocator;</span>
<span class="line" id="L370"> <span class="tok-kw">const</span> input = <span class="tok-str">&quot;The quick brown fox\r\njumped over the lazy dog!&quot;</span>;</span>
<span class="line" id="L371"> <span class="tok-kw">const</span> got = <span class="tok-kw">try</span> wrap(allocator, input, <span class="tok-number">10</span>, <span class="tok-number">3</span>);</span>
<span class="line" id="L372"> <span class="tok-kw">defer</span> allocator.free(got);</span>
<span class="line" id="L373"> <span class="tok-kw">const</span> want = <span class="tok-str">&quot;The quick\n brown \nfox jumped\n over the\n lazy dog\n!&quot;</span>;</span>
<span class="line" id="L374"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(want, got);</span>
<span class="line" id="L375">}</span>
<span class="line" id="L376"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,902 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>normalizer/Normalizer.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! Normalizer contains functions and methods that implement Unicode Normalization algorithms. You can normalize strings</span></span>
<span class="line" id="L2"><span class="tok-comment">//! into NFC, NFKC, NFD, and NFKD normalization forms (see `nfc`, `nfkc`, `nfd`, and `nfkd`). You can also test for</span></span>
<span class="line" id="L3"><span class="tok-comment">//! string equality under different parameters related to normalization (see `eql`, `eqlCaseless`, `eqlIdentifiers`).</span></span>
<span class="line" id="L4"></span>
<span class="line" id="L5"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L6"></span>
<span class="line" id="L7"><span class="tok-kw">const</span> CodePointIterator = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../segmenter/CodePoint.zig&quot;</span>).CodePointIterator;</span>
<span class="line" id="L8"><span class="tok-kw">const</span> case_fold_map = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/case_folding.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">const</span> ccc_map = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_combining_class.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> hangul_map = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/hangul_syllable_type.zig&quot;</span>);</span>
<span class="line" id="L11"><span class="tok-kw">const</span> norm_props = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/derived_normalization_props.zig&quot;</span>);</span>
<span class="line" id="L12"></span>
<span class="line" id="L13"><span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L14"></span>
<span class="line" id="L15">nfc_map: std.AutoHashMap([<span class="tok-number">2</span>]<span class="tok-type">u21</span>, <span class="tok-type">u21</span>),</span>
<span class="line" id="L16">nfd_map: std.AutoHashMap(<span class="tok-type">u21</span>, [<span class="tok-number">2</span>]<span class="tok-type">u21</span>),</span>
<span class="line" id="L17">nfkd_map: std.AutoHashMap(<span class="tok-type">u21</span>, [<span class="tok-number">18</span>]<span class="tok-type">u21</span>),</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(allocator: std.mem.Allocator) !Self {</span>
<span class="line" id="L20"> <span class="tok-kw">var</span> self = Self{</span>
<span class="line" id="L21"> .nfc_map = std.AutoHashMap([<span class="tok-number">2</span>]<span class="tok-type">u21</span>, <span class="tok-type">u21</span>).init(allocator),</span>
<span class="line" id="L22"> .nfd_map = std.AutoHashMap(<span class="tok-type">u21</span>, [<span class="tok-number">2</span>]<span class="tok-type">u21</span>).init(allocator),</span>
<span class="line" id="L23"> .nfkd_map = std.AutoHashMap(<span class="tok-type">u21</span>, [<span class="tok-number">18</span>]<span class="tok-type">u21</span>).init(allocator),</span>
<span class="line" id="L24"> };</span>
<span class="line" id="L25"> <span class="tok-kw">errdefer</span> self.deinit();</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"> <span class="tok-comment">// Canonical compositions</span>
</span>
<span class="line" id="L28"> <span class="tok-kw">const</span> decompressor = std.compress.deflate.decompressor;</span>
<span class="line" id="L29"> <span class="tok-kw">const</span> comp_file = <span class="tok-builtin">@embedFile</span>(<span class="tok-str">&quot;../autogen/canonical_compositions.txt.deflate&quot;</span>);</span>
<span class="line" id="L30"> <span class="tok-kw">var</span> comp_stream = std.io.fixedBufferStream(comp_file);</span>
<span class="line" id="L31"> <span class="tok-kw">var</span> comp_decomp = <span class="tok-kw">try</span> decompressor(allocator, comp_stream.reader(), <span class="tok-null">null</span>);</span>
<span class="line" id="L32"> <span class="tok-kw">defer</span> comp_decomp.deinit();</span>
<span class="line" id="L33"></span>
<span class="line" id="L34"> <span class="tok-kw">var</span> comp_buf = std.io.bufferedReader(comp_decomp.reader());</span>
<span class="line" id="L35"> <span class="tok-kw">const</span> comp_reader = comp_buf.reader();</span>
<span class="line" id="L36"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4096</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L37"></span>
<span class="line" id="L38"> <span class="tok-kw">while</span> (<span class="tok-kw">try</span> comp_reader.readUntilDelimiterOrEof(&amp;buf, <span class="tok-str">'\n'</span>)) |line| {</span>
<span class="line" id="L39"> <span class="tok-kw">if</span> (line.len == <span class="tok-number">0</span>) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L40"> <span class="tok-kw">var</span> fields = std.mem.split(<span class="tok-type">u8</span>, line, <span class="tok-str">&quot;;&quot;</span>);</span>
<span class="line" id="L41"> <span class="tok-kw">const</span> cp_a = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>);</span>
<span class="line" id="L42"> <span class="tok-kw">const</span> cp_b = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>);</span>
<span class="line" id="L43"> <span class="tok-kw">const</span> cp_c = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>);</span>
<span class="line" id="L44"> <span class="tok-kw">try</span> self.nfc_map.put(.{ cp_a, cp_b }, cp_c);</span>
<span class="line" id="L45"> }</span>
<span class="line" id="L46"></span>
<span class="line" id="L47"> <span class="tok-comment">// Canonical decompositions</span>
</span>
<span class="line" id="L48"> <span class="tok-kw">const</span> decomp_file = <span class="tok-builtin">@embedFile</span>(<span class="tok-str">&quot;../autogen/canonical_decompositions.txt.deflate&quot;</span>);</span>
<span class="line" id="L49"> <span class="tok-kw">var</span> decomp_stream = std.io.fixedBufferStream(decomp_file);</span>
<span class="line" id="L50"> <span class="tok-kw">var</span> decomp_decomp = <span class="tok-kw">try</span> decompressor(allocator, decomp_stream.reader(), <span class="tok-null">null</span>);</span>
<span class="line" id="L51"> <span class="tok-kw">defer</span> decomp_decomp.deinit();</span>
<span class="line" id="L52"></span>
<span class="line" id="L53"> <span class="tok-kw">var</span> decomp_buf = std.io.bufferedReader(decomp_decomp.reader());</span>
<span class="line" id="L54"> <span class="tok-kw">const</span> decomp_reader = decomp_buf.reader();</span>
<span class="line" id="L55"></span>
<span class="line" id="L56"> <span class="tok-kw">while</span> (<span class="tok-kw">try</span> decomp_reader.readUntilDelimiterOrEof(&amp;buf, <span class="tok-str">'\n'</span>)) |line| {</span>
<span class="line" id="L57"> <span class="tok-kw">if</span> (line.len == <span class="tok-number">0</span>) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L58"> <span class="tok-kw">var</span> fields = std.mem.split(<span class="tok-type">u8</span>, line, <span class="tok-str">&quot;;&quot;</span>);</span>
<span class="line" id="L59"> <span class="tok-kw">const</span> cp_a = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>);</span>
<span class="line" id="L60"> <span class="tok-kw">const</span> cp_b = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>);</span>
<span class="line" id="L61"> <span class="tok-kw">const</span> cp_c = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>);</span>
<span class="line" id="L62"> <span class="tok-kw">try</span> self.nfd_map.put(cp_a, .{ cp_b, cp_c });</span>
<span class="line" id="L63"> }</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> <span class="tok-comment">// Compatibility decompositions</span>
</span>
<span class="line" id="L66"> <span class="tok-kw">const</span> dekomp_file = <span class="tok-builtin">@embedFile</span>(<span class="tok-str">&quot;../autogen/compatibility_decompositions.txt.deflate&quot;</span>);</span>
<span class="line" id="L67"> <span class="tok-kw">var</span> dekomp_stream = std.io.fixedBufferStream(dekomp_file);</span>
<span class="line" id="L68"> <span class="tok-kw">var</span> dekomp_decomp = <span class="tok-kw">try</span> decompressor(allocator, dekomp_stream.reader(), <span class="tok-null">null</span>);</span>
<span class="line" id="L69"> <span class="tok-kw">defer</span> dekomp_decomp.deinit();</span>
<span class="line" id="L70"></span>
<span class="line" id="L71"> <span class="tok-kw">var</span> dekomp_buf = std.io.bufferedReader(dekomp_decomp.reader());</span>
<span class="line" id="L72"> <span class="tok-kw">const</span> dekomp_reader = dekomp_buf.reader();</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"> <span class="tok-kw">while</span> (<span class="tok-kw">try</span> dekomp_reader.readUntilDelimiterOrEof(&amp;buf, <span class="tok-str">'\n'</span>)) |line| {</span>
<span class="line" id="L75"> <span class="tok-kw">if</span> (line.len == <span class="tok-number">0</span>) <span class="tok-kw">continue</span>;</span>
<span class="line" id="L76"> <span class="tok-kw">var</span> fields = std.mem.split(<span class="tok-type">u8</span>, line, <span class="tok-str">&quot;;&quot;</span>);</span>
<span class="line" id="L77"> <span class="tok-kw">const</span> cp_a = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, fields.next().?, <span class="tok-number">16</span>);</span>
<span class="line" id="L78"> <span class="tok-kw">var</span> cps = [_]<span class="tok-type">u21</span>{<span class="tok-number">0</span>} ** <span class="tok-number">18</span>;</span>
<span class="line" id="L79"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"> <span class="tok-kw">while</span> (fields.next()) |cp| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L82"> cps[i] = <span class="tok-kw">try</span> std.fmt.parseInt(<span class="tok-type">u21</span>, cp, <span class="tok-number">16</span>);</span>
<span class="line" id="L83"> }</span>
<span class="line" id="L84"></span>
<span class="line" id="L85"> <span class="tok-kw">try</span> self.nfkd_map.put(cp_a, cps);</span>
<span class="line" id="L86"> }</span>
<span class="line" id="L87"></span>
<span class="line" id="L88"> <span class="tok-kw">return</span> self;</span>
<span class="line" id="L89">}</span>
<span class="line" id="L90"></span>
<span class="line" id="L91"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L92"> self.nfc_map.deinit();</span>
<span class="line" id="L93"> self.nfd_map.deinit();</span>
<span class="line" id="L94"> self.nfkd_map.deinit();</span>
<span class="line" id="L95">}</span>
<span class="line" id="L96"></span>
<span class="line" id="L97"><span class="tok-kw">test</span> <span class="tok-str">&quot;init / deinit&quot;</span> {</span>
<span class="line" id="L98"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(std.testing.allocator);</span>
<span class="line" id="L99"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L100">}</span>
<span class="line" id="L101"><span class="tok-comment">// Hangul processing utilities.</span>
</span>
<span class="line" id="L102"><span class="tok-kw">fn</span> <span class="tok-fn">isHangulPrecomposed</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L103"> <span class="tok-kw">if</span> (hangul_map.syllableType(cp)) |kind| <span class="tok-kw">return</span> kind == .LV <span class="tok-kw">or</span> kind == .LVT;</span>
<span class="line" id="L104"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L105">}</span>
<span class="line" id="L106"></span>
<span class="line" id="L107"><span class="tok-kw">const</span> SBase: <span class="tok-type">u21</span> = <span class="tok-number">0xAC00</span>;</span>
<span class="line" id="L108"><span class="tok-kw">const</span> LBase: <span class="tok-type">u21</span> = <span class="tok-number">0x1100</span>;</span>
<span class="line" id="L109"><span class="tok-kw">const</span> VBase: <span class="tok-type">u21</span> = <span class="tok-number">0x1161</span>;</span>
<span class="line" id="L110"><span class="tok-kw">const</span> TBase: <span class="tok-type">u21</span> = <span class="tok-number">0x11A7</span>;</span>
<span class="line" id="L111"><span class="tok-kw">const</span> LCount: <span class="tok-type">u21</span> = <span class="tok-number">19</span>;</span>
<span class="line" id="L112"><span class="tok-kw">const</span> VCount: <span class="tok-type">u21</span> = <span class="tok-number">21</span>;</span>
<span class="line" id="L113"><span class="tok-kw">const</span> TCount: <span class="tok-type">u21</span> = <span class="tok-number">28</span>;</span>
<span class="line" id="L114"><span class="tok-kw">const</span> NCount: <span class="tok-type">u21</span> = <span class="tok-number">588</span>; <span class="tok-comment">// VCount * TCount</span>
</span>
<span class="line" id="L115"><span class="tok-kw">const</span> SCount: <span class="tok-type">u21</span> = <span class="tok-number">11172</span>; <span class="tok-comment">// LCount * NCount</span>
</span>
<span class="line" id="L116"></span>
<span class="line" id="L117"><span class="tok-kw">fn</span> <span class="tok-fn">decomposeHangul</span>(cp: <span class="tok-type">u21</span>) [<span class="tok-number">3</span>]<span class="tok-type">u21</span> {</span>
<span class="line" id="L118"> <span class="tok-kw">const</span> SIndex: <span class="tok-type">u21</span> = cp - SBase;</span>
<span class="line" id="L119"> <span class="tok-kw">const</span> LIndex: <span class="tok-type">u21</span> = SIndex / NCount;</span>
<span class="line" id="L120"> <span class="tok-kw">const</span> VIndex: <span class="tok-type">u21</span> = (SIndex % NCount) / TCount;</span>
<span class="line" id="L121"> <span class="tok-kw">const</span> TIndex: <span class="tok-type">u21</span> = SIndex % TCount;</span>
<span class="line" id="L122"> <span class="tok-kw">const</span> LPart: <span class="tok-type">u21</span> = LBase + LIndex;</span>
<span class="line" id="L123"> <span class="tok-kw">const</span> VPart: <span class="tok-type">u21</span> = VBase + VIndex;</span>
<span class="line" id="L124"> <span class="tok-kw">var</span> TPart: <span class="tok-type">u21</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L125"> <span class="tok-kw">if</span> (TIndex != <span class="tok-number">0</span>) TPart = TBase + TIndex;</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"> <span class="tok-kw">return</span> [<span class="tok-number">3</span>]<span class="tok-type">u21</span>{ LPart, VPart, TPart };</span>
<span class="line" id="L128">}</span>
<span class="line" id="L129"></span>
<span class="line" id="L130"><span class="tok-kw">fn</span> <span class="tok-fn">composeHangulCanon</span>(lv: <span class="tok-type">u21</span>, t: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L131"> std.debug.assert(<span class="tok-number">0x11A8</span> &lt;= t <span class="tok-kw">and</span> t &lt;= <span class="tok-number">0x11C2</span>);</span>
<span class="line" id="L132"> <span class="tok-kw">return</span> lv + (t - TBase);</span>
<span class="line" id="L133">}</span>
<span class="line" id="L134"></span>
<span class="line" id="L135"><span class="tok-kw">fn</span> <span class="tok-fn">composeHangulFull</span>(l: <span class="tok-type">u21</span>, v: <span class="tok-type">u21</span>, t: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L136"> std.debug.assert(<span class="tok-number">0x1100</span> &lt;= l <span class="tok-kw">and</span> l &lt;= <span class="tok-number">0x1112</span>);</span>
<span class="line" id="L137"> std.debug.assert(<span class="tok-number">0x1161</span> &lt;= v <span class="tok-kw">and</span> v &lt;= <span class="tok-number">0x1175</span>);</span>
<span class="line" id="L138"> <span class="tok-kw">const</span> LIndex = l - LBase;</span>
<span class="line" id="L139"> <span class="tok-kw">const</span> VIndex = v - VBase;</span>
<span class="line" id="L140"> <span class="tok-kw">const</span> LVIndex = LIndex * NCount + VIndex * TCount;</span>
<span class="line" id="L141"></span>
<span class="line" id="L142"> <span class="tok-kw">if</span> (t == <span class="tok-number">0</span>) <span class="tok-kw">return</span> SBase + LVIndex;</span>
<span class="line" id="L143"></span>
<span class="line" id="L144"> std.debug.assert(<span class="tok-number">0x11A8</span> &lt;= t <span class="tok-kw">and</span> t &lt;= <span class="tok-number">0x11C2</span>);</span>
<span class="line" id="L145"> <span class="tok-kw">const</span> TIndex = t - TBase;</span>
<span class="line" id="L146"></span>
<span class="line" id="L147"> <span class="tok-kw">return</span> SBase + LVIndex + TIndex;</span>
<span class="line" id="L148">}</span>
<span class="line" id="L149"></span>
<span class="line" id="L150"><span class="tok-kw">const</span> Form = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L151"> nfc,</span>
<span class="line" id="L152"> nfd,</span>
<span class="line" id="L153"> nfkc,</span>
<span class="line" id="L154"> nfkd,</span>
<span class="line" id="L155"> same,</span>
<span class="line" id="L156">};</span>
<span class="line" id="L157"></span>
<span class="line" id="L158"><span class="tok-kw">const</span> Decomp = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L159"> form: Form = .nfd,</span>
<span class="line" id="L160"> cps: [<span class="tok-number">18</span>]<span class="tok-type">u21</span> = [_]<span class="tok-type">u21</span>{<span class="tok-number">0</span>} ** <span class="tok-number">18</span>,</span>
<span class="line" id="L161">};</span>
<span class="line" id="L162"></span>
<span class="line" id="L163"><span class="tok-comment">/// `mapping` retrieves the decomposition mapping for a code point as per the UCD.</span></span>
<span class="line" id="L164"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">mapping</span>(self: Self, cp: <span class="tok-type">u21</span>, form: Form) Decomp {</span>
<span class="line" id="L165"> std.debug.assert(form == .nfd <span class="tok-kw">or</span> form == .nfkd);</span>
<span class="line" id="L166"></span>
<span class="line" id="L167"> <span class="tok-kw">var</span> dc = Decomp{ .form = .same };</span>
<span class="line" id="L168"> dc.cps[<span class="tok-number">0</span>] = cp;</span>
<span class="line" id="L169"></span>
<span class="line" id="L170"> <span class="tok-kw">if</span> (self.nfkd_map.get(cp)) |array| {</span>
<span class="line" id="L171"> <span class="tok-kw">if</span> (form != .nfd) {</span>
<span class="line" id="L172"> dc.form = .nfkd;</span>
<span class="line" id="L173"> <span class="tok-builtin">@memcpy</span>(dc.cps[<span class="tok-number">0</span>..array.len], &amp;array);</span>
<span class="line" id="L174"> }</span>
<span class="line" id="L175"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (self.nfd_map.get(cp)) |array| {</span>
<span class="line" id="L176"> dc.form = .nfd;</span>
<span class="line" id="L177"> <span class="tok-builtin">@memcpy</span>(dc.cps[<span class="tok-number">0</span>..array.len], &amp;array);</span>
<span class="line" id="L178"> }</span>
<span class="line" id="L179"></span>
<span class="line" id="L180"> <span class="tok-kw">return</span> dc;</span>
<span class="line" id="L181">}</span>
<span class="line" id="L182"></span>
<span class="line" id="L183"><span class="tok-comment">/// `decompose` a code point to the specified normalization form, which should be either `.nfd` or `.nfkd`.</span></span>
<span class="line" id="L184"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">decompose</span>(self: Self, cp: <span class="tok-type">u21</span>, form: Form) Decomp {</span>
<span class="line" id="L185"> std.debug.assert(form == .nfd <span class="tok-kw">or</span> form == .nfkd);</span>
<span class="line" id="L186"></span>
<span class="line" id="L187"> <span class="tok-kw">var</span> dc = Decomp{ .form = form };</span>
<span class="line" id="L188"></span>
<span class="line" id="L189"> <span class="tok-comment">// ASCII or NFD / NFKD quick checks.</span>
</span>
<span class="line" id="L190"> <span class="tok-kw">if</span> (cp &lt;= <span class="tok-number">127</span> <span class="tok-kw">or</span> (form == .nfd <span class="tok-kw">and</span> norm_props.isNfd(cp)) <span class="tok-kw">or</span> (form == .nfkd <span class="tok-kw">and</span> norm_props.isNfkd(cp))) {</span>
<span class="line" id="L191"> dc.cps[<span class="tok-number">0</span>] = cp;</span>
<span class="line" id="L192"> <span class="tok-kw">return</span> dc;</span>
<span class="line" id="L193"> }</span>
<span class="line" id="L194"></span>
<span class="line" id="L195"> <span class="tok-comment">// Hangul precomposed syllable full decomposition.</span>
</span>
<span class="line" id="L196"> <span class="tok-kw">if</span> (isHangulPrecomposed(cp)) {</span>
<span class="line" id="L197"> <span class="tok-kw">const</span> cps = decomposeHangul(cp);</span>
<span class="line" id="L198"> <span class="tok-builtin">@memcpy</span>(dc.cps[<span class="tok-number">0</span>..cps.len], &amp;cps);</span>
<span class="line" id="L199"> <span class="tok-kw">return</span> dc;</span>
<span class="line" id="L200"> }</span>
<span class="line" id="L201"></span>
<span class="line" id="L202"> <span class="tok-comment">// Full decomposition.</span>
</span>
<span class="line" id="L203"> <span class="tok-kw">var</span> result_index: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L204"> <span class="tok-kw">var</span> work_index: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L205"></span>
<span class="line" id="L206"> <span class="tok-comment">// Start work with argument code point.</span>
</span>
<span class="line" id="L207"> <span class="tok-kw">var</span> work = [_]<span class="tok-type">u21</span>{cp} ++ [_]<span class="tok-type">u21</span>{<span class="tok-number">0</span>} ** <span class="tok-number">17</span>;</span>
<span class="line" id="L208"></span>
<span class="line" id="L209"> <span class="tok-kw">while</span> (work_index &gt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L210"> <span class="tok-comment">// Look at previous code point in work queue.</span>
</span>
<span class="line" id="L211"> work_index -= <span class="tok-number">1</span>;</span>
<span class="line" id="L212"> <span class="tok-kw">const</span> next = work[work_index];</span>
<span class="line" id="L213"> <span class="tok-kw">const</span> m = self.mapping(next, form);</span>
<span class="line" id="L214"></span>
<span class="line" id="L215"> <span class="tok-comment">// No more of decompositions for this code point.</span>
</span>
<span class="line" id="L216"> <span class="tok-kw">if</span> (m.form == .same) {</span>
<span class="line" id="L217"> dc.cps[result_index] = m.cps[<span class="tok-number">0</span>];</span>
<span class="line" id="L218"> result_index += <span class="tok-number">1</span>;</span>
<span class="line" id="L219"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L220"> }</span>
<span class="line" id="L221"></span>
<span class="line" id="L222"> <span class="tok-comment">// Find last index of decomposition.</span>
</span>
<span class="line" id="L223"> <span class="tok-kw">const</span> m_last = <span class="tok-kw">for</span> (m.cps, <span class="tok-number">0</span>..) |mcp, i| {</span>
<span class="line" id="L224"> <span class="tok-kw">if</span> (mcp == <span class="tok-number">0</span>) <span class="tok-kw">break</span> i;</span>
<span class="line" id="L225"> } <span class="tok-kw">else</span> m.cps.len;</span>
<span class="line" id="L226"></span>
<span class="line" id="L227"> <span class="tok-comment">// Work backwards through decomposition.</span>
</span>
<span class="line" id="L228"> <span class="tok-comment">// `i` starts at 1 because m_last is 1 past the last code point.</span>
</span>
<span class="line" id="L229"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L230"> <span class="tok-kw">while</span> (i &lt;= m_last) : ({</span>
<span class="line" id="L231"> i += <span class="tok-number">1</span>;</span>
<span class="line" id="L232"> work_index += <span class="tok-number">1</span>;</span>
<span class="line" id="L233"> }) {</span>
<span class="line" id="L234"> work[work_index] = m.cps[m_last - i];</span>
<span class="line" id="L235"> }</span>
<span class="line" id="L236"> }</span>
<span class="line" id="L237"></span>
<span class="line" id="L238"> <span class="tok-kw">return</span> dc;</span>
<span class="line" id="L239">}</span>
<span class="line" id="L240"></span>
<span class="line" id="L241"><span class="tok-kw">test</span> <span class="tok-str">&quot;decompose&quot;</span> {</span>
<span class="line" id="L242"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L243"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L244"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L245"></span>
<span class="line" id="L246"> <span class="tok-kw">var</span> dc = n.decompose(<span class="tok-str">'é'</span>, .nfd);</span>
<span class="line" id="L247"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfd);</span>
<span class="line" id="L248"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'e'</span>, <span class="tok-str">'\u{301}'</span> }, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">2</span>]);</span>
<span class="line" id="L249"></span>
<span class="line" id="L250"> dc = n.decompose(<span class="tok-str">'\u{1e0a}'</span>, .nfd);</span>
<span class="line" id="L251"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfd);</span>
<span class="line" id="L252"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'D'</span>, <span class="tok-str">'\u{307}'</span> }, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">2</span>]);</span>
<span class="line" id="L253"></span>
<span class="line" id="L254"> dc = n.decompose(<span class="tok-str">'\u{1e0a}'</span>, .nfkd);</span>
<span class="line" id="L255"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfkd);</span>
<span class="line" id="L256"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'D'</span>, <span class="tok-str">'\u{307}'</span> }, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">2</span>]);</span>
<span class="line" id="L257"></span>
<span class="line" id="L258"> dc = n.decompose(<span class="tok-str">'\u{3189}'</span>, .nfd);</span>
<span class="line" id="L259"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfd);</span>
<span class="line" id="L260"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{<span class="tok-str">'\u{3189}'</span>}, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">1</span>]);</span>
<span class="line" id="L261"></span>
<span class="line" id="L262"> dc = n.decompose(<span class="tok-str">'\u{3189}'</span>, .nfkd);</span>
<span class="line" id="L263"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfkd);</span>
<span class="line" id="L264"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{<span class="tok-str">'\u{1188}'</span>}, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">1</span>]);</span>
<span class="line" id="L265"></span>
<span class="line" id="L266"> dc = n.decompose(<span class="tok-str">'\u{ace1}'</span>, .nfd);</span>
<span class="line" id="L267"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfd);</span>
<span class="line" id="L268"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'\u{1100}'</span>, <span class="tok-str">'\u{1169}'</span>, <span class="tok-str">'\u{11a8}'</span> }, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">3</span>]);</span>
<span class="line" id="L269"></span>
<span class="line" id="L270"> dc = n.decompose(<span class="tok-str">'\u{ace1}'</span>, .nfkd);</span>
<span class="line" id="L271"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfkd);</span>
<span class="line" id="L272"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'\u{1100}'</span>, <span class="tok-str">'\u{1169}'</span>, <span class="tok-str">'\u{11a8}'</span> }, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">3</span>]);</span>
<span class="line" id="L273"></span>
<span class="line" id="L274"> dc = n.decompose(<span class="tok-str">'\u{3d3}'</span>, .nfd);</span>
<span class="line" id="L275"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfd);</span>
<span class="line" id="L276"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'\u{3d2}'</span>, <span class="tok-str">'\u{301}'</span> }, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">2</span>]);</span>
<span class="line" id="L277"></span>
<span class="line" id="L278"> dc = n.decompose(<span class="tok-str">'\u{3d3}'</span>, .nfkd);</span>
<span class="line" id="L279"> <span class="tok-kw">try</span> std.testing.expect(dc.form == .nfkd);</span>
<span class="line" id="L280"> <span class="tok-kw">try</span> std.testing.expectEqualSlices(<span class="tok-type">u21</span>, &amp;[_]<span class="tok-type">u21</span>{ <span class="tok-str">'\u{3a5}'</span>, <span class="tok-str">'\u{301}'</span> }, dc.cps[<span class="tok-number">0</span>..<span class="tok-number">2</span>]);</span>
<span class="line" id="L281">}</span>
<span class="line" id="L282"></span>
<span class="line" id="L283"><span class="tok-comment">// Some quick checks.</span>
</span>
<span class="line" id="L284"></span>
<span class="line" id="L285"><span class="tok-kw">fn</span> <span class="tok-fn">onlyAscii</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L286"> <span class="tok-kw">return</span> <span class="tok-kw">for</span> (str) |b| {</span>
<span class="line" id="L287"> <span class="tok-kw">if</span> (b &gt; <span class="tok-number">127</span>) <span class="tok-kw">break</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L288"> } <span class="tok-kw">else</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L289">}</span>
<span class="line" id="L290"></span>
<span class="line" id="L291"><span class="tok-kw">fn</span> <span class="tok-fn">onlyLatin1</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L292"> <span class="tok-kw">var</span> cp_iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L293"> <span class="tok-kw">return</span> <span class="tok-kw">while</span> (cp_iter.next()) |cp| {</span>
<span class="line" id="L294"> <span class="tok-kw">if</span> (cp.code &gt; <span class="tok-number">256</span>) <span class="tok-kw">break</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L295"> } <span class="tok-kw">else</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L296">}</span>
<span class="line" id="L297"></span>
<span class="line" id="L298"><span class="tok-comment">/// Returned from various functions in this namespace. Remember to call `deinit` to free any allocated memory.</span></span>
<span class="line" id="L299"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Result = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L300"> allocator: ?std.mem.Allocator = <span class="tok-null">null</span>,</span>
<span class="line" id="L301"> slice: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L302"></span>
<span class="line" id="L303"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Result) <span class="tok-type">void</span> {</span>
<span class="line" id="L304"> <span class="tok-kw">if</span> (self.allocator) |allocator| allocator.free(self.slice);</span>
<span class="line" id="L305"> }</span>
<span class="line" id="L306">};</span>
<span class="line" id="L307"></span>
<span class="line" id="L308"><span class="tok-comment">// Compares code points by Canonical Combining Class order.</span>
</span>
<span class="line" id="L309"><span class="tok-kw">fn</span> <span class="tok-fn">cccLess</span>(_: <span class="tok-type">void</span>, lhs: <span class="tok-type">u21</span>, rhs: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L310"> <span class="tok-kw">return</span> ccc_map.combiningClass(lhs) &lt; ccc_map.combiningClass(rhs);</span>
<span class="line" id="L311">}</span>
<span class="line" id="L312"></span>
<span class="line" id="L313"><span class="tok-comment">// Applies the Canonical Sorting Algorithm.</span>
</span>
<span class="line" id="L314"><span class="tok-kw">fn</span> <span class="tok-fn">canonicalSort</span>(cps: []<span class="tok-type">u21</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L315"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L316"> <span class="tok-kw">while</span> (i &lt; cps.len) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L317"> <span class="tok-kw">const</span> start: <span class="tok-type">usize</span> = i;</span>
<span class="line" id="L318"> <span class="tok-kw">while</span> (i &lt; cps.len <span class="tok-kw">and</span> ccc_map.combiningClass(cps[i]) != <span class="tok-number">0</span>) : (i += <span class="tok-number">1</span>) {}</span>
<span class="line" id="L319"> std.mem.sort(<span class="tok-type">u21</span>, cps[start..i], {}, cccLess);</span>
<span class="line" id="L320"> }</span>
<span class="line" id="L321">}</span>
<span class="line" id="L322"></span>
<span class="line" id="L323"><span class="tok-comment">/// Normalize `str` to NFD.</span></span>
<span class="line" id="L324"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">nfd</span>(self: Self, allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !Result {</span>
<span class="line" id="L325"> <span class="tok-kw">return</span> self.nfxd(allocator, str, .nfd);</span>
<span class="line" id="L326">}</span>
<span class="line" id="L327"></span>
<span class="line" id="L328"><span class="tok-comment">/// Normalize `str` to NFKD.</span></span>
<span class="line" id="L329"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">nfkd</span>(self: Self, allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !Result {</span>
<span class="line" id="L330"> <span class="tok-kw">return</span> self.nfxd(allocator, str, .nfkd);</span>
<span class="line" id="L331">}</span>
<span class="line" id="L332"></span>
<span class="line" id="L333"><span class="tok-kw">fn</span> <span class="tok-fn">nfxd</span>(self: Self, allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, form: Form) !Result {</span>
<span class="line" id="L334"> <span class="tok-comment">// Quick checks.</span>
</span>
<span class="line" id="L335"> <span class="tok-kw">if</span> (onlyAscii(str)) <span class="tok-kw">return</span> Result{ .slice = str };</span>
<span class="line" id="L336"></span>
<span class="line" id="L337"> <span class="tok-kw">var</span> dcp_list = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u21</span>).initCapacity(allocator, str.len + str.len / <span class="tok-number">2</span>);</span>
<span class="line" id="L338"> <span class="tok-kw">defer</span> dcp_list.deinit();</span>
<span class="line" id="L339"></span>
<span class="line" id="L340"> <span class="tok-kw">var</span> cp_iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L341"> <span class="tok-kw">while</span> (cp_iter.next()) |cp| {</span>
<span class="line" id="L342"> <span class="tok-kw">const</span> dc = self.decompose(cp.code, form);</span>
<span class="line" id="L343"> <span class="tok-kw">const</span> slice = <span class="tok-kw">for</span> (dc.cps, <span class="tok-number">0</span>..) |dcp, i| {</span>
<span class="line" id="L344"> <span class="tok-kw">if</span> (dcp == <span class="tok-number">0</span>) <span class="tok-kw">break</span> dc.cps[<span class="tok-number">0</span>..i];</span>
<span class="line" id="L345"> } <span class="tok-kw">else</span> dc.cps[<span class="tok-number">0</span>..];</span>
<span class="line" id="L346"> <span class="tok-kw">try</span> dcp_list.appendSlice(slice);</span>
<span class="line" id="L347"> }</span>
<span class="line" id="L348"></span>
<span class="line" id="L349"> canonicalSort(dcp_list.items);</span>
<span class="line" id="L350"></span>
<span class="line" id="L351"> <span class="tok-kw">var</span> dstr_list = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u8</span>).initCapacity(allocator, dcp_list.items.len * <span class="tok-number">4</span>);</span>
<span class="line" id="L352"> <span class="tok-kw">defer</span> dstr_list.deinit();</span>
<span class="line" id="L353"></span>
<span class="line" id="L354"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L355"> <span class="tok-kw">for</span> (dcp_list.items) |dcp| {</span>
<span class="line" id="L356"> <span class="tok-kw">const</span> len = <span class="tok-kw">try</span> std.unicode.utf8Encode(dcp, &amp;buf);</span>
<span class="line" id="L357"> dstr_list.appendSliceAssumeCapacity(buf[<span class="tok-number">0</span>..len]);</span>
<span class="line" id="L358"> }</span>
<span class="line" id="L359"></span>
<span class="line" id="L360"> <span class="tok-kw">return</span> Result{ .allocator = allocator, .slice = <span class="tok-kw">try</span> dstr_list.toOwnedSlice() };</span>
<span class="line" id="L361">}</span>
<span class="line" id="L362"></span>
<span class="line" id="L363"><span class="tok-kw">test</span> <span class="tok-str">&quot;nfd ASCII / no-alloc&quot;</span> {</span>
<span class="line" id="L364"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L365"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L366"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L367"></span>
<span class="line" id="L368"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> n.nfd(allocator, <span class="tok-str">&quot;Hello World!&quot;</span>);</span>
<span class="line" id="L369"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L370"></span>
<span class="line" id="L371"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(<span class="tok-str">&quot;Hello World!&quot;</span>, result.slice);</span>
<span class="line" id="L372">}</span>
<span class="line" id="L373"></span>
<span class="line" id="L374"><span class="tok-kw">test</span> <span class="tok-str">&quot;nfd !ASCII / alloc&quot;</span> {</span>
<span class="line" id="L375"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L376"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L377"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L378"></span>
<span class="line" id="L379"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> n.nfd(allocator, <span class="tok-str">&quot;Héllo World! \u{3d3}&quot;</span>);</span>
<span class="line" id="L380"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L381"></span>
<span class="line" id="L382"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(<span class="tok-str">&quot;He\u{301}llo World! \u{3d2}\u{301}&quot;</span>, result.slice);</span>
<span class="line" id="L383">}</span>
<span class="line" id="L384"></span>
<span class="line" id="L385"><span class="tok-kw">test</span> <span class="tok-str">&quot;nfkd ASCII / no-alloc&quot;</span> {</span>
<span class="line" id="L386"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L387"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L388"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L389"></span>
<span class="line" id="L390"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> n.nfkd(allocator, <span class="tok-str">&quot;Hello World!&quot;</span>);</span>
<span class="line" id="L391"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L392"></span>
<span class="line" id="L393"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(<span class="tok-str">&quot;Hello World!&quot;</span>, result.slice);</span>
<span class="line" id="L394">}</span>
<span class="line" id="L395"></span>
<span class="line" id="L396"><span class="tok-kw">test</span> <span class="tok-str">&quot;nfkd !ASCII / alloc&quot;</span> {</span>
<span class="line" id="L397"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L398"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L399"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L400"></span>
<span class="line" id="L401"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> n.nfkd(allocator, <span class="tok-str">&quot;Héllo World! \u{3d3}&quot;</span>);</span>
<span class="line" id="L402"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L403"></span>
<span class="line" id="L404"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(<span class="tok-str">&quot;He\u{301}llo World! \u{3a5}\u{301}&quot;</span>, result.slice);</span>
<span class="line" id="L405">}</span>
<span class="line" id="L406"></span>
<span class="line" id="L407"><span class="tok-comment">// Composition utilities.</span>
</span>
<span class="line" id="L408"></span>
<span class="line" id="L409"><span class="tok-kw">fn</span> <span class="tok-fn">isHangul</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L410"> <span class="tok-kw">return</span> cp &gt;= <span class="tok-number">0x1100</span> <span class="tok-kw">and</span> hangul_map.syllableType(cp) != <span class="tok-null">null</span>;</span>
<span class="line" id="L411">}</span>
<span class="line" id="L412"></span>
<span class="line" id="L413"><span class="tok-kw">fn</span> <span class="tok-fn">isStarter</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L414"> <span class="tok-kw">return</span> ccc_map.combiningClass(cp) == <span class="tok-number">0</span>;</span>
<span class="line" id="L415">}</span>
<span class="line" id="L416"></span>
<span class="line" id="L417"><span class="tok-kw">fn</span> <span class="tok-fn">isCombining</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L418"> <span class="tok-kw">return</span> ccc_map.combiningClass(cp) != <span class="tok-number">0</span>;</span>
<span class="line" id="L419">}</span>
<span class="line" id="L420"></span>
<span class="line" id="L421"><span class="tok-kw">fn</span> <span class="tok-fn">isNonHangulStarter</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L422"> <span class="tok-kw">return</span> !isHangul(cp) <span class="tok-kw">and</span> isStarter(cp);</span>
<span class="line" id="L423">}</span>
<span class="line" id="L424"></span>
<span class="line" id="L425"><span class="tok-comment">/// Normalizes `str` to NFC.</span></span>
<span class="line" id="L426"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">nfc</span>(self: Self, allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !Result {</span>
<span class="line" id="L427"> <span class="tok-kw">return</span> self.nfxc(allocator, str, .nfc);</span>
<span class="line" id="L428">}</span>
<span class="line" id="L429"></span>
<span class="line" id="L430"><span class="tok-comment">/// Normalizes `str` to NFKC.</span></span>
<span class="line" id="L431"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">nfkc</span>(self: Self, allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !Result {</span>
<span class="line" id="L432"> <span class="tok-kw">return</span> self.nfxc(allocator, str, .nfkc);</span>
<span class="line" id="L433">}</span>
<span class="line" id="L434"></span>
<span class="line" id="L435"><span class="tok-kw">fn</span> <span class="tok-fn">nfxc</span>(self: Self, allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, form: Form) !Result {</span>
<span class="line" id="L436"> <span class="tok-comment">// Quick checks.</span>
</span>
<span class="line" id="L437"> <span class="tok-kw">if</span> (onlyAscii(str)) <span class="tok-kw">return</span> Result{ .slice = str };</span>
<span class="line" id="L438"> <span class="tok-kw">if</span> (form == .nfc <span class="tok-kw">and</span> onlyLatin1(str)) <span class="tok-kw">return</span> Result{ .slice = str };</span>
<span class="line" id="L439"></span>
<span class="line" id="L440"> <span class="tok-comment">// Decompose first.</span>
</span>
<span class="line" id="L441"> <span class="tok-kw">var</span> d_result = <span class="tok-kw">if</span> (form == .nfc)</span>
<span class="line" id="L442"> <span class="tok-kw">try</span> self.nfd(allocator, str)</span>
<span class="line" id="L443"> <span class="tok-kw">else</span></span>
<span class="line" id="L444"> <span class="tok-kw">try</span> self.nfkd(allocator, str);</span>
<span class="line" id="L445"> <span class="tok-kw">defer</span> d_result.deinit();</span>
<span class="line" id="L446"></span>
<span class="line" id="L447"> <span class="tok-comment">// Get code points.</span>
</span>
<span class="line" id="L448"> <span class="tok-kw">var</span> cp_iter = CodePointIterator{ .bytes = d_result.slice };</span>
<span class="line" id="L449"></span>
<span class="line" id="L450"> <span class="tok-kw">var</span> d_list = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u21</span>).initCapacity(allocator, d_result.slice.len);</span>
<span class="line" id="L451"> <span class="tok-kw">defer</span> d_list.deinit();</span>
<span class="line" id="L452"></span>
<span class="line" id="L453"> <span class="tok-kw">while</span> (cp_iter.next()) |cp| d_list.appendAssumeCapacity(cp.code);</span>
<span class="line" id="L454"></span>
<span class="line" id="L455"> <span class="tok-comment">// Compose</span>
</span>
<span class="line" id="L456"> <span class="tok-kw">const</span> tombstone = <span class="tok-number">0xe000</span>; <span class="tok-comment">// Start of BMP Private Use Area</span>
</span>
<span class="line" id="L457"></span>
<span class="line" id="L458"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L459"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">1</span>; <span class="tok-comment">// start at second code point.</span>
</span>
<span class="line" id="L460"> <span class="tok-kw">var</span> deleted: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L461"></span>
<span class="line" id="L462"> block_check: <span class="tok-kw">while</span> (i &lt; d_list.items.len) : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L463"> <span class="tok-kw">const</span> C = d_list.items[i];</span>
<span class="line" id="L464"> <span class="tok-kw">var</span> starter_index: ?<span class="tok-type">usize</span> = <span class="tok-null">null</span>;</span>
<span class="line" id="L465"> <span class="tok-kw">var</span> j: <span class="tok-type">usize</span> = i;</span>
<span class="line" id="L466"></span>
<span class="line" id="L467"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L468"> j -= <span class="tok-number">1</span>;</span>
<span class="line" id="L469"></span>
<span class="line" id="L470"> <span class="tok-comment">// Check for starter.</span>
</span>
<span class="line" id="L471"> <span class="tok-kw">if</span> (ccc_map.combiningClass(d_list.items[j]) == <span class="tok-number">0</span>) {</span>
<span class="line" id="L472"> <span class="tok-kw">if</span> (i - j &gt; <span class="tok-number">1</span>) { <span class="tok-comment">// If there's distance between the starting point and the current position.</span>
</span>
<span class="line" id="L473"> <span class="tok-kw">for</span> (d_list.items[(j + <span class="tok-number">1</span>)..i]) |B| {</span>
<span class="line" id="L474"> <span class="tok-comment">// Check for blocking conditions.</span>
</span>
<span class="line" id="L475"> <span class="tok-kw">if</span> (isHangul(C)) {</span>
<span class="line" id="L476"> <span class="tok-kw">if</span> (isCombining(B) <span class="tok-kw">or</span> isNonHangulStarter(B)) <span class="tok-kw">continue</span> :block_check;</span>
<span class="line" id="L477"> }</span>
<span class="line" id="L478"> <span class="tok-kw">if</span> (ccc_map.combiningClass(B) &gt;= ccc_map.combiningClass(C)) <span class="tok-kw">continue</span> :block_check;</span>
<span class="line" id="L479"> }</span>
<span class="line" id="L480"> }</span>
<span class="line" id="L481"></span>
<span class="line" id="L482"> <span class="tok-comment">// Found starter at j.</span>
</span>
<span class="line" id="L483"> starter_index = j;</span>
<span class="line" id="L484"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L485"> }</span>
<span class="line" id="L486"></span>
<span class="line" id="L487"> <span class="tok-kw">if</span> (j == <span class="tok-number">0</span>) <span class="tok-kw">break</span>;</span>
<span class="line" id="L488"> }</span>
<span class="line" id="L489"></span>
<span class="line" id="L490"> <span class="tok-kw">if</span> (starter_index) |sidx| {</span>
<span class="line" id="L491"> <span class="tok-kw">const</span> L = d_list.items[sidx];</span>
<span class="line" id="L492"> <span class="tok-kw">var</span> processed_hangul = <span class="tok-null">false</span>;</span>
<span class="line" id="L493"></span>
<span class="line" id="L494"> <span class="tok-kw">if</span> (isHangul(L) <span class="tok-kw">and</span> isHangul(C)) {</span>
<span class="line" id="L495"> <span class="tok-kw">const</span> l_stype = hangul_map.syllableType(L).?;</span>
<span class="line" id="L496"> <span class="tok-kw">const</span> c_stype = hangul_map.syllableType(C).?;</span>
<span class="line" id="L497"></span>
<span class="line" id="L498"> <span class="tok-kw">if</span> (l_stype == .LV <span class="tok-kw">and</span> c_stype == .T) {</span>
<span class="line" id="L499"> <span class="tok-comment">// LV, T</span>
</span>
<span class="line" id="L500"> d_list.items[sidx] = composeHangulCanon(L, C);</span>
<span class="line" id="L501"> d_list.items[i] = tombstone; <span class="tok-comment">// Mark for deletion.</span>
</span>
<span class="line" id="L502"> processed_hangul = <span class="tok-null">true</span>;</span>
<span class="line" id="L503"> }</span>
<span class="line" id="L504"></span>
<span class="line" id="L505"> <span class="tok-kw">if</span> (l_stype == .L <span class="tok-kw">and</span> c_stype == .V) {</span>
<span class="line" id="L506"> <span class="tok-comment">// Handle L, V. L, V, T is handled via main loop.</span>
</span>
<span class="line" id="L507"> d_list.items[sidx] = composeHangulFull(L, C, <span class="tok-number">0</span>);</span>
<span class="line" id="L508"> d_list.items[i] = tombstone; <span class="tok-comment">// Mark for deletion.</span>
</span>
<span class="line" id="L509"> processed_hangul = <span class="tok-null">true</span>;</span>
<span class="line" id="L510"> }</span>
<span class="line" id="L511"></span>
<span class="line" id="L512"> <span class="tok-kw">if</span> (processed_hangul) deleted += <span class="tok-number">1</span>;</span>
<span class="line" id="L513"> }</span>
<span class="line" id="L514"></span>
<span class="line" id="L515"> <span class="tok-kw">if</span> (!processed_hangul) {</span>
<span class="line" id="L516"> <span class="tok-comment">// L -&gt; C not Hangul.</span>
</span>
<span class="line" id="L517"> <span class="tok-kw">if</span> (self.nfc_map.get(.{ L, C })) |P| {</span>
<span class="line" id="L518"> <span class="tok-kw">if</span> (!norm_props.isFcx(P)) {</span>
<span class="line" id="L519"> d_list.items[sidx] = P;</span>
<span class="line" id="L520"> d_list.items[i] = tombstone; <span class="tok-comment">// Mark for deletion.</span>
</span>
<span class="line" id="L521"> deleted += <span class="tok-number">1</span>;</span>
<span class="line" id="L522"> }</span>
<span class="line" id="L523"> }</span>
<span class="line" id="L524"> }</span>
<span class="line" id="L525"> }</span>
<span class="line" id="L526"> }</span>
<span class="line" id="L527"></span>
<span class="line" id="L528"> <span class="tok-comment">// Check if finished.</span>
</span>
<span class="line" id="L529"> <span class="tok-kw">if</span> (deleted == <span class="tok-number">0</span>) {</span>
<span class="line" id="L530"> <span class="tok-kw">var</span> cstr_list = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u8</span>).initCapacity(allocator, d_list.items.len * <span class="tok-number">4</span>);</span>
<span class="line" id="L531"> <span class="tok-kw">defer</span> cstr_list.deinit();</span>
<span class="line" id="L532"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L533"></span>
<span class="line" id="L534"> <span class="tok-kw">for</span> (d_list.items) |cp| {</span>
<span class="line" id="L535"> <span class="tok-kw">if</span> (cp == tombstone) <span class="tok-kw">continue</span>; <span class="tok-comment">// &quot;Delete&quot;</span>
</span>
<span class="line" id="L536"> <span class="tok-kw">const</span> len = <span class="tok-kw">try</span> std.unicode.utf8Encode(cp, &amp;buf);</span>
<span class="line" id="L537"> cstr_list.appendSliceAssumeCapacity(buf[<span class="tok-number">0</span>..len]);</span>
<span class="line" id="L538"> }</span>
<span class="line" id="L539"></span>
<span class="line" id="L540"> <span class="tok-kw">return</span> Result{ .allocator = allocator, .slice = <span class="tok-kw">try</span> cstr_list.toOwnedSlice() };</span>
<span class="line" id="L541"> }</span>
<span class="line" id="L542"></span>
<span class="line" id="L543"> <span class="tok-comment">// Otherwise update code points list.</span>
</span>
<span class="line" id="L544"> <span class="tok-kw">var</span> tmp_d_list = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u21</span>).initCapacity(allocator, d_list.items.len - deleted);</span>
<span class="line" id="L545"> <span class="tok-kw">defer</span> tmp_d_list.deinit();</span>
<span class="line" id="L546"></span>
<span class="line" id="L547"> <span class="tok-kw">for</span> (d_list.items) |cp| {</span>
<span class="line" id="L548"> <span class="tok-kw">if</span> (cp != tombstone) tmp_d_list.appendAssumeCapacity(cp);</span>
<span class="line" id="L549"> }</span>
<span class="line" id="L550"></span>
<span class="line" id="L551"> d_list.clearRetainingCapacity();</span>
<span class="line" id="L552"> d_list.appendSliceAssumeCapacity(tmp_d_list.items);</span>
<span class="line" id="L553"> }</span>
<span class="line" id="L554">}</span>
<span class="line" id="L555"></span>
<span class="line" id="L556"><span class="tok-kw">test</span> <span class="tok-str">&quot;nfc&quot;</span> {</span>
<span class="line" id="L557"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L558"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L559"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L560"></span>
<span class="line" id="L561"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> n.nfc(allocator, <span class="tok-str">&quot;Complex char: \u{3D2}\u{301}&quot;</span>);</span>
<span class="line" id="L562"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L563"></span>
<span class="line" id="L564"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(<span class="tok-str">&quot;Complex char: \u{3D3}&quot;</span>, result.slice);</span>
<span class="line" id="L565">}</span>
<span class="line" id="L566"></span>
<span class="line" id="L567"><span class="tok-kw">test</span> <span class="tok-str">&quot;nfkc&quot;</span> {</span>
<span class="line" id="L568"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L569"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L570"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L571"></span>
<span class="line" id="L572"> <span class="tok-kw">var</span> result = <span class="tok-kw">try</span> n.nfkc(allocator, <span class="tok-str">&quot;Complex char: \u{03A5}\u{0301}&quot;</span>);</span>
<span class="line" id="L573"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L574"></span>
<span class="line" id="L575"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(<span class="tok-str">&quot;Complex char: \u{038E}&quot;</span>, result.slice);</span>
<span class="line" id="L576">}</span>
<span class="line" id="L577"></span>
<span class="line" id="L578"><span class="tok-comment">/// Tests for equality as per Unicode rules for Identifiers.</span></span>
<span class="line" id="L579"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eqlIdentifiers</span>(allocator: std.mem.Allocator, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">bool</span> {</span>
<span class="line" id="L580"> <span class="tok-kw">var</span> list_a = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u21</span>).initCapacity(allocator, a.len);</span>
<span class="line" id="L581"> <span class="tok-kw">defer</span> list_a.deinit();</span>
<span class="line" id="L582"> <span class="tok-kw">var</span> list_b = <span class="tok-kw">try</span> std.ArrayList(<span class="tok-type">u21</span>).initCapacity(allocator, b.len);</span>
<span class="line" id="L583"> <span class="tok-kw">defer</span> list_b.deinit();</span>
<span class="line" id="L584"></span>
<span class="line" id="L585"> <span class="tok-kw">const</span> Item = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L586"> str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L587"> list: *std.ArrayList(<span class="tok-type">u21</span>),</span>
<span class="line" id="L588"> };</span>
<span class="line" id="L589"></span>
<span class="line" id="L590"> <span class="tok-kw">const</span> items = [_]Item{</span>
<span class="line" id="L591"> .{ .str = a, .list = &amp;list_a },</span>
<span class="line" id="L592"> .{ .str = b, .list = &amp;list_b },</span>
<span class="line" id="L593"> };</span>
<span class="line" id="L594"></span>
<span class="line" id="L595"> <span class="tok-kw">for</span> (items) |item| {</span>
<span class="line" id="L596"> <span class="tok-kw">var</span> cp_iter = CodePointIterator{ .bytes = item.str };</span>
<span class="line" id="L597"> <span class="tok-kw">while</span> (cp_iter.next()) |cp| {</span>
<span class="line" id="L598"> <span class="tok-kw">if</span> (norm_props.toNfkcCaseFold(cp.code)) |nfkcf| {</span>
<span class="line" id="L599"> <span class="tok-kw">for</span> (nfkcf) |c| {</span>
<span class="line" id="L600"> <span class="tok-kw">if</span> (c == <span class="tok-number">0</span>) <span class="tok-kw">break</span>;</span>
<span class="line" id="L601"> item.list.appendAssumeCapacity(c);</span>
<span class="line" id="L602"> }</span>
<span class="line" id="L603"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L604"> item.list.appendAssumeCapacity(cp.code); <span class="tok-comment">// maps to itself</span>
</span>
<span class="line" id="L605"> }</span>
<span class="line" id="L606"> }</span>
<span class="line" id="L607"> }</span>
<span class="line" id="L608"></span>
<span class="line" id="L609"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u21</span>, list_a.items, list_b.items);</span>
<span class="line" id="L610">}</span>
<span class="line" id="L611"></span>
<span class="line" id="L612"><span class="tok-kw">test</span> <span class="tok-str">&quot;eqlIdentifiers&quot;</span> {</span>
<span class="line" id="L613"> <span class="tok-kw">try</span> std.testing.expect(<span class="tok-kw">try</span> eqlIdentifiers(std.testing.allocator, <span class="tok-str">&quot;Foé&quot;</span>, <span class="tok-str">&quot;foé&quot;</span>));</span>
<span class="line" id="L614">}</span>
<span class="line" id="L615"></span>
<span class="line" id="L616"><span class="tok-comment">/// Tests for equality of `a` and `b` after normalizing to NFD.</span></span>
<span class="line" id="L617"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eql</span>(self: Self, allocator: std.mem.Allocator, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">bool</span> {</span>
<span class="line" id="L618"> <span class="tok-kw">var</span> norm_result_a = <span class="tok-kw">try</span> self.nfd(allocator, a);</span>
<span class="line" id="L619"> <span class="tok-kw">defer</span> norm_result_a.deinit();</span>
<span class="line" id="L620"> <span class="tok-kw">var</span> norm_result_b = <span class="tok-kw">try</span> self.nfd(allocator, b);</span>
<span class="line" id="L621"> <span class="tok-kw">defer</span> norm_result_b.deinit();</span>
<span class="line" id="L622"></span>
<span class="line" id="L623"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, norm_result_a.slice, norm_result_b.slice);</span>
<span class="line" id="L624">}</span>
<span class="line" id="L625"></span>
<span class="line" id="L626"><span class="tok-kw">test</span> <span class="tok-str">&quot;eql&quot;</span> {</span>
<span class="line" id="L627"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L628"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L629"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L630"></span>
<span class="line" id="L631"> <span class="tok-kw">try</span> std.testing.expect(<span class="tok-kw">try</span> n.eql(allocator, <span class="tok-str">&quot;foé&quot;</span>, <span class="tok-str">&quot;foe\u{0301}&quot;</span>));</span>
<span class="line" id="L632"> <span class="tok-kw">try</span> std.testing.expect(<span class="tok-kw">try</span> n.eql(allocator, <span class="tok-str">&quot;foϓ&quot;</span>, <span class="tok-str">&quot;fo\u{03D2}\u{0301}&quot;</span>));</span>
<span class="line" id="L633">}</span>
<span class="line" id="L634"></span>
<span class="line" id="L635"><span class="tok-kw">fn</span> <span class="tok-fn">requiresNfdBeforeCaseFold</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L636"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (cp) {</span>
<span class="line" id="L637"> <span class="tok-number">0x0345</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L638"> <span class="tok-number">0x1F80</span>...<span class="tok-number">0x1FAF</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L639"> <span class="tok-number">0x1FB2</span>...<span class="tok-number">0x1FB4</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L640"> <span class="tok-number">0x1FB7</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L641"> <span class="tok-number">0x1FBC</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L642"> <span class="tok-number">0x1FC2</span>...<span class="tok-number">0x1FC4</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L643"> <span class="tok-number">0x1FC7</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L644"> <span class="tok-number">0x1FCC</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L645"> <span class="tok-number">0x1FF2</span>...<span class="tok-number">0x1FF4</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L646"> <span class="tok-number">0x1FF7</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L647"> <span class="tok-number">0x1FFC</span> =&gt; <span class="tok-null">true</span>,</span>
<span class="line" id="L648"> <span class="tok-kw">else</span> =&gt; <span class="tok-null">false</span>,</span>
<span class="line" id="L649"> };</span>
<span class="line" id="L650">}</span>
<span class="line" id="L651"></span>
<span class="line" id="L652"><span class="tok-kw">fn</span> <span class="tok-fn">requiresPreNfd</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L653"> <span class="tok-kw">var</span> cp_iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L654"></span>
<span class="line" id="L655"> <span class="tok-kw">return</span> <span class="tok-kw">while</span> (cp_iter.next()) |cp| {</span>
<span class="line" id="L656"> <span class="tok-kw">if</span> (requiresNfdBeforeCaseFold(cp.code)) <span class="tok-kw">break</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L657"> } <span class="tok-kw">else</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L658">}</span>
<span class="line" id="L659"></span>
<span class="line" id="L660"><span class="tok-comment">/// `eqlCaseless` tests for equality of `a` and `b` after normalizing to NFD and ignoring letter case.</span></span>
<span class="line" id="L661"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eqlCaseless</span>(self: Self, allocator: std.mem.Allocator, a: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, b: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !<span class="tok-type">bool</span> {</span>
<span class="line" id="L662"> <span class="tok-comment">// The long winding road of normalized caseless matching...</span>
</span>
<span class="line" id="L663"> <span class="tok-comment">// NFD(CaseFold(NFD(str))) or NFD(CaseFold(str))</span>
</span>
<span class="line" id="L664"> <span class="tok-kw">var</span> norm_result_a: Result = Result{ .slice = a };</span>
<span class="line" id="L665"> <span class="tok-kw">if</span> (requiresPreNfd(a)) {</span>
<span class="line" id="L666"> <span class="tok-kw">if</span> (!self.isFcd(a)) {</span>
<span class="line" id="L667"> norm_result_a = <span class="tok-kw">try</span> self.nfd(allocator, a);</span>
<span class="line" id="L668"> }</span>
<span class="line" id="L669"> }</span>
<span class="line" id="L670"> <span class="tok-kw">defer</span> norm_result_a.deinit();</span>
<span class="line" id="L671"></span>
<span class="line" id="L672"> <span class="tok-kw">const</span> cf_a = <span class="tok-kw">try</span> case_fold_map.caseFoldStr(allocator, norm_result_a.slice);</span>
<span class="line" id="L673"> <span class="tok-kw">defer</span> allocator.free(cf_a);</span>
<span class="line" id="L674"> norm_result_a.deinit();</span>
<span class="line" id="L675"> norm_result_a = <span class="tok-kw">try</span> self.nfd(allocator, cf_a);</span>
<span class="line" id="L676"></span>
<span class="line" id="L677"> <span class="tok-kw">var</span> norm_result_b: Result = Result{ .slice = b };</span>
<span class="line" id="L678"> <span class="tok-kw">if</span> (requiresPreNfd(b)) {</span>
<span class="line" id="L679"> <span class="tok-kw">if</span> (!self.isFcd(b)) {</span>
<span class="line" id="L680"> norm_result_b = <span class="tok-kw">try</span> self.nfd(allocator, b);</span>
<span class="line" id="L681"> }</span>
<span class="line" id="L682"> }</span>
<span class="line" id="L683"> <span class="tok-kw">defer</span> norm_result_b.deinit();</span>
<span class="line" id="L684"></span>
<span class="line" id="L685"> <span class="tok-kw">const</span> cf_b = <span class="tok-kw">try</span> case_fold_map.caseFoldStr(allocator, norm_result_b.slice);</span>
<span class="line" id="L686"> <span class="tok-kw">defer</span> allocator.free(cf_b);</span>
<span class="line" id="L687"> norm_result_b.deinit();</span>
<span class="line" id="L688"> norm_result_b = <span class="tok-kw">try</span> self.nfd(allocator, cf_b);</span>
<span class="line" id="L689"></span>
<span class="line" id="L690"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, norm_result_a.slice, norm_result_b.slice);</span>
<span class="line" id="L691">}</span>
<span class="line" id="L692"></span>
<span class="line" id="L693"><span class="tok-kw">test</span> <span class="tok-str">&quot;eqlCaseless&quot;</span> {</span>
<span class="line" id="L694"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L695"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L696"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L697"></span>
<span class="line" id="L698"> <span class="tok-kw">try</span> std.testing.expect(<span class="tok-kw">try</span> n.eqlCaseless(allocator, <span class="tok-str">&quot;Foϓ&quot;</span>, <span class="tok-str">&quot;fo\u{03D2}\u{0301}&quot;</span>));</span>
<span class="line" id="L699"> <span class="tok-kw">try</span> std.testing.expect(<span class="tok-kw">try</span> n.eqlCaseless(allocator, <span class="tok-str">&quot;FOÉ&quot;</span>, <span class="tok-str">&quot;foe\u{0301}&quot;</span>)); <span class="tok-comment">// foÉ == foé</span>
</span>
<span class="line" id="L700">}</span>
<span class="line" id="L701"></span>
<span class="line" id="L702"><span class="tok-comment">// FCD</span>
</span>
<span class="line" id="L703"><span class="tok-kw">fn</span> <span class="tok-fn">getLeadCcc</span>(self: Self, cp: <span class="tok-type">u21</span>) <span class="tok-type">u8</span> {</span>
<span class="line" id="L704"> <span class="tok-kw">const</span> dc = self.mapping(cp, .nfd);</span>
<span class="line" id="L705"> <span class="tok-kw">return</span> ccc_map.combiningClass(dc.cps[<span class="tok-number">0</span>]);</span>
<span class="line" id="L706">}</span>
<span class="line" id="L707"></span>
<span class="line" id="L708"><span class="tok-kw">fn</span> <span class="tok-fn">getTrailCcc</span>(self: Self, cp: <span class="tok-type">u21</span>) <span class="tok-type">u8</span> {</span>
<span class="line" id="L709"> <span class="tok-kw">const</span> dc = self.mapping(cp, .nfd);</span>
<span class="line" id="L710"> <span class="tok-kw">const</span> len = <span class="tok-kw">for</span> (dc.cps, <span class="tok-number">0</span>..) |dcp, i| {</span>
<span class="line" id="L711"> <span class="tok-kw">if</span> (dcp == <span class="tok-number">0</span>) <span class="tok-kw">break</span> i;</span>
<span class="line" id="L712"> } <span class="tok-kw">else</span> dc.cps.len;</span>
<span class="line" id="L713"> <span class="tok-kw">return</span> ccc_map.combiningClass(dc.cps[len -| <span class="tok-number">1</span>]);</span>
<span class="line" id="L714">}</span>
<span class="line" id="L715"></span>
<span class="line" id="L716"><span class="tok-comment">/// Fast check to detect if a string is already in NFC or NFD form.</span></span>
<span class="line" id="L717"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isFcd</span>(self: Self, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L718"> <span class="tok-kw">var</span> prev_ccc: <span class="tok-type">u8</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L719"> <span class="tok-kw">var</span> cp_iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L720"></span>
<span class="line" id="L721"> <span class="tok-kw">return</span> <span class="tok-kw">while</span> (cp_iter.next()) |cp| {</span>
<span class="line" id="L722"> <span class="tok-kw">const</span> ccc = self.getLeadCcc(cp.code);</span>
<span class="line" id="L723"> <span class="tok-kw">if</span> (ccc != <span class="tok-number">0</span> <span class="tok-kw">and</span> ccc &lt; prev_ccc) <span class="tok-kw">break</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L724"> prev_ccc = self.getTrailCcc(cp.code);</span>
<span class="line" id="L725"> } <span class="tok-kw">else</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L726">}</span>
<span class="line" id="L727"></span>
<span class="line" id="L728"><span class="tok-kw">test</span> <span class="tok-str">&quot;isFcd&quot;</span> {</span>
<span class="line" id="L729"> <span class="tok-kw">const</span> allocator = std.testing.allocator;</span>
<span class="line" id="L730"> <span class="tok-kw">var</span> n = <span class="tok-kw">try</span> init(allocator);</span>
<span class="line" id="L731"> <span class="tok-kw">defer</span> n.deinit();</span>
<span class="line" id="L732"></span>
<span class="line" id="L733"> <span class="tok-kw">const</span> is_nfc = <span class="tok-str">&quot;José \u{3D3}&quot;</span>;</span>
<span class="line" id="L734"> <span class="tok-kw">try</span> std.testing.expect(n.isFcd(is_nfc));</span>
<span class="line" id="L735"></span>
<span class="line" id="L736"> <span class="tok-kw">const</span> is_nfd = <span class="tok-str">&quot;Jose\u{301} \u{3d2}\u{301}&quot;</span>;</span>
<span class="line" id="L737"> <span class="tok-kw">try</span> std.testing.expect(n.isFcd(is_nfd));</span>
<span class="line" id="L738"></span>
<span class="line" id="L739"> <span class="tok-kw">const</span> not_fcd = <span class="tok-str">&quot;Jose\u{301} \u{3d2}\u{315}\u{301}&quot;</span>;</span>
<span class="line" id="L740"> <span class="tok-kw">try</span> std.testing.expect(!n.isFcd(not_fcd));</span>
<span class="line" id="L741">}</span>
<span class="line" id="L742"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,250 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>segmenter/CodePoint.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `CodePoint` represents a Unicode code point by its code, length, and offset in the source bytes.</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"></span>
<span class="line" id="L5">code: <span class="tok-type">u21</span>,</span>
<span class="line" id="L6">len: <span class="tok-type">u3</span>,</span>
<span class="line" id="L7">offset: <span class="tok-type">usize</span>,</span>
<span class="line" id="L8"></span>
<span class="line" id="L9"><span class="tok-kw">const</span> CodePoint = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-comment">/// `CodePointIterator` iterates a string one `CodePoint` at-a-time.</span></span>
<span class="line" id="L12"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CodePointIterator = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L13"> bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L14"> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">next</span>(self: *CodePointIterator) ?CodePoint {</span>
<span class="line" id="L17"> <span class="tok-kw">if</span> (self.i &gt;= self.bytes.len) <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L18"></span>
<span class="line" id="L19"> <span class="tok-kw">if</span> (self.bytes[self.i] &lt; <span class="tok-number">128</span>) {</span>
<span class="line" id="L20"> <span class="tok-comment">// ASCII fast path</span>
</span>
<span class="line" id="L21"> <span class="tok-kw">const</span> cp = CodePoint{</span>
<span class="line" id="L22"> .code = self.bytes[self.i],</span>
<span class="line" id="L23"> .len = <span class="tok-number">1</span>,</span>
<span class="line" id="L24"> .offset = self.i,</span>
<span class="line" id="L25"> };</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"> self.i += <span class="tok-number">1</span>;</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"> <span class="tok-kw">return</span> cp;</span>
<span class="line" id="L30"> }</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"> <span class="tok-kw">var</span> cp = CodePoint{</span>
<span class="line" id="L33"> .code = <span class="tok-null">undefined</span>,</span>
<span class="line" id="L34"> .len = blk: {</span>
<span class="line" id="L35"> <span class="tok-kw">break</span> :blk <span class="tok-kw">switch</span> (self.bytes[self.i]) {</span>
<span class="line" id="L36"> <span class="tok-number">0b0000_0000</span>...<span class="tok-number">0b0111_1111</span> =&gt; <span class="tok-number">1</span>,</span>
<span class="line" id="L37"> <span class="tok-number">0b1100_0000</span>...<span class="tok-number">0b1101_1111</span> =&gt; <span class="tok-number">2</span>,</span>
<span class="line" id="L38"> <span class="tok-number">0b1110_0000</span>...<span class="tok-number">0b1110_1111</span> =&gt; <span class="tok-number">3</span>,</span>
<span class="line" id="L39"> <span class="tok-number">0b1111_0000</span>...<span class="tok-number">0b1111_0111</span> =&gt; <span class="tok-number">4</span>,</span>
<span class="line" id="L40"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L41"> };</span>
<span class="line" id="L42"> },</span>
<span class="line" id="L43"> .offset = self.i,</span>
<span class="line" id="L44"> };</span>
<span class="line" id="L45"></span>
<span class="line" id="L46"> self.i += cp.len;</span>
<span class="line" id="L47"> <span class="tok-kw">const</span> cp_bytes = self.bytes[self.i - cp.len .. self.i];</span>
<span class="line" id="L48"></span>
<span class="line" id="L49"> cp.code = <span class="tok-kw">switch</span> (cp.len) {</span>
<span class="line" id="L50"> <span class="tok-number">2</span> =&gt; (<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, (cp_bytes[<span class="tok-number">0</span>] &amp; <span class="tok-number">0b00011111</span>)) &lt;&lt; <span class="tok-number">6</span>) | (cp_bytes[<span class="tok-number">1</span>] &amp; <span class="tok-number">0b00111111</span>),</span>
<span class="line" id="L51"></span>
<span class="line" id="L52"> <span class="tok-number">3</span> =&gt; (((<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, (cp_bytes[<span class="tok-number">0</span>] &amp; <span class="tok-number">0b00001111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L53"> (cp_bytes[<span class="tok-number">1</span>] &amp; <span class="tok-number">0b00111111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L54"> (cp_bytes[<span class="tok-number">2</span>] &amp; <span class="tok-number">0b00111111</span>),</span>
<span class="line" id="L55"></span>
<span class="line" id="L56"> <span class="tok-number">4</span> =&gt; (((((<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, (cp_bytes[<span class="tok-number">0</span>] &amp; <span class="tok-number">0b00000111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L57"> (cp_bytes[<span class="tok-number">1</span>] &amp; <span class="tok-number">0b00111111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L58"> (cp_bytes[<span class="tok-number">2</span>] &amp; <span class="tok-number">0b00111111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L59"> (cp_bytes[<span class="tok-number">3</span>] &amp; <span class="tok-number">0b00111111</span>),</span>
<span class="line" id="L60"></span>
<span class="line" id="L61"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L62"> };</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"> <span class="tok-kw">return</span> cp;</span>
<span class="line" id="L65"> }</span>
<span class="line" id="L66"></span>
<span class="line" id="L67"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">peek</span>(self: *CodePointIterator) ?CodePoint {</span>
<span class="line" id="L68"> <span class="tok-kw">const</span> saved_i = self.i;</span>
<span class="line" id="L69"> <span class="tok-kw">defer</span> self.i = saved_i;</span>
<span class="line" id="L70"> <span class="tok-kw">return</span> self.next();</span>
<span class="line" id="L71"> }</span>
<span class="line" id="L72">};</span>
<span class="line" id="L73"></span>
<span class="line" id="L74"><span class="tok-kw">test</span> <span class="tok-str">&quot;CodePointIterator peek&quot;</span> {</span>
<span class="line" id="L75"> <span class="tok-kw">var</span> iter = CodePointIterator{ .bytes = <span class="tok-str">&quot;Hi&quot;</span> };</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, <span class="tok-str">'H'</span>), iter.next().?.code);</span>
<span class="line" id="L78"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, <span class="tok-str">'i'</span>), iter.peek().?.code);</span>
<span class="line" id="L79"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, <span class="tok-str">'i'</span>), iter.next().?.code);</span>
<span class="line" id="L80"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(?CodePoint, <span class="tok-null">null</span>), iter.peek());</span>
<span class="line" id="L81"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(?CodePoint, <span class="tok-null">null</span>), iter.next());</span>
<span class="line" id="L82">}</span>
<span class="line" id="L83"></span>
<span class="line" id="L84"><span class="tok-comment">/// `readCodePoint` returns the next code point code as a `u21` in the given reader, or null at end-of-input.</span></span>
<span class="line" id="L85"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">readCodePoint</span>(reader: <span class="tok-kw">anytype</span>) !?<span class="tok-type">u21</span> {</span>
<span class="line" id="L86"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L87"></span>
<span class="line" id="L88"> buf[<span class="tok-number">0</span>] = reader.readByte() <span class="tok-kw">catch</span> |err| <span class="tok-kw">switch</span> (err) {</span>
<span class="line" id="L89"> <span class="tok-kw">error</span>.EndOfStream =&gt; <span class="tok-kw">return</span> <span class="tok-null">null</span>,</span>
<span class="line" id="L90"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> err,</span>
<span class="line" id="L91"> };</span>
<span class="line" id="L92"></span>
<span class="line" id="L93"> <span class="tok-kw">if</span> (buf[<span class="tok-number">0</span>] &lt; <span class="tok-number">128</span>) <span class="tok-kw">return</span> <span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, buf[<span class="tok-number">0</span>]);</span>
<span class="line" id="L94"></span>
<span class="line" id="L95"> <span class="tok-kw">const</span> len: <span class="tok-type">u3</span> = <span class="tok-kw">switch</span> (buf[<span class="tok-number">0</span>]) {</span>
<span class="line" id="L96"> <span class="tok-number">0b1100_0000</span>...<span class="tok-number">0b1101_1111</span> =&gt; <span class="tok-number">2</span>,</span>
<span class="line" id="L97"> <span class="tok-number">0b1110_0000</span>...<span class="tok-number">0b1110_1111</span> =&gt; <span class="tok-number">3</span>,</span>
<span class="line" id="L98"> <span class="tok-number">0b1111_0000</span>...<span class="tok-number">0b1111_0111</span> =&gt; <span class="tok-number">4</span>,</span>
<span class="line" id="L99"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidUtf8,</span>
<span class="line" id="L100"> };</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"> <span class="tok-kw">const</span> read = <span class="tok-kw">try</span> reader.read(buf[<span class="tok-number">1</span>..len]);</span>
<span class="line" id="L103"></span>
<span class="line" id="L104"> <span class="tok-kw">if</span> (read &lt; len - <span class="tok-number">1</span>) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidUtf8;</span>
<span class="line" id="L105"></span>
<span class="line" id="L106"> <span class="tok-kw">return</span> <span class="tok-kw">switch</span> (len) {</span>
<span class="line" id="L107"> <span class="tok-number">2</span> =&gt; (<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, (buf[<span class="tok-number">0</span>] &amp; <span class="tok-number">0b00011111</span>)) &lt;&lt; <span class="tok-number">6</span>) | (buf[<span class="tok-number">1</span>] &amp; <span class="tok-number">0b00111111</span>),</span>
<span class="line" id="L108"></span>
<span class="line" id="L109"> <span class="tok-number">3</span> =&gt; (((<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, (buf[<span class="tok-number">0</span>] &amp; <span class="tok-number">0b00001111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L110"> (buf[<span class="tok-number">1</span>] &amp; <span class="tok-number">0b00111111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L111"> (buf[<span class="tok-number">2</span>] &amp; <span class="tok-number">0b00111111</span>),</span>
<span class="line" id="L112"></span>
<span class="line" id="L113"> <span class="tok-number">4</span> =&gt; (((((<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, (buf[<span class="tok-number">0</span>] &amp; <span class="tok-number">0b00000111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L114"> (buf[<span class="tok-number">1</span>] &amp; <span class="tok-number">0b00111111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L115"> (buf[<span class="tok-number">2</span>] &amp; <span class="tok-number">0b00111111</span>)) &lt;&lt; <span class="tok-number">6</span>) |</span>
<span class="line" id="L116"> (buf[<span class="tok-number">3</span>] &amp; <span class="tok-number">0b00111111</span>),</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"> <span class="tok-kw">else</span> =&gt; <span class="tok-kw">unreachable</span>,</span>
<span class="line" id="L119"> };</span>
<span class="line" id="L120">}</span>
<span class="line" id="L121"></span>
<span class="line" id="L122"><span class="tok-kw">test</span> <span class="tok-str">&quot;readCodePoint&quot;</span> {</span>
<span class="line" id="L123"> <span class="tok-kw">var</span> buf = <span class="tok-str">&quot;abé😹&quot;</span>.*;</span>
<span class="line" id="L124"> <span class="tok-kw">var</span> fis = std.io.fixedBufferStream(&amp;buf);</span>
<span class="line" id="L125"> <span class="tok-kw">const</span> reader = fis.reader();</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, <span class="tok-str">'a'</span>), (<span class="tok-kw">try</span> readCodePoint(reader)).?);</span>
<span class="line" id="L128"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, <span class="tok-str">'b'</span>), (<span class="tok-kw">try</span> readCodePoint(reader)).?);</span>
<span class="line" id="L129"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, <span class="tok-str">'é'</span>), (<span class="tok-kw">try</span> readCodePoint(reader)).?);</span>
<span class="line" id="L130"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">u21</span>, <span class="tok-str">'😹'</span>), (<span class="tok-kw">try</span> readCodePoint(reader)).?);</span>
<span class="line" id="L131"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(?<span class="tok-type">u21</span>, <span class="tok-null">null</span>), <span class="tok-kw">try</span> readCodePoint(reader));</span>
<span class="line" id="L132">}</span>
<span class="line" id="L133"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,542 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>segmenter/Grapheme.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `Grapheme` represents a Unicode grapheme cluster by its length and offset in the source bytes.</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> unicode = std.unicode;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> CodePoint = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;CodePoint.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> CodePointIterator = CodePoint.CodePointIterator;</span>
<span class="line" id="L8"><span class="tok-kw">const</span> readCodePoint = CodePoint.readCodePoint;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> emoji = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/emoji_data.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">const</span> gbp = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/grapheme_break_property.zig&quot;</span>);</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Grapheme = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L13"></span>
<span class="line" id="L14">len: <span class="tok-type">usize</span>,</span>
<span class="line" id="L15">offset: <span class="tok-type">usize</span>,</span>
<span class="line" id="L16"></span>
<span class="line" id="L17"><span class="tok-comment">/// `eql` comparse `str` with the bytes of this grapheme cluster in `src` for equality.</span></span>
<span class="line" id="L18"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eql</span>(self: Grapheme, src: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, other: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L19"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, src[self.offset .. self.offset + self.len], other);</span>
<span class="line" id="L20">}</span>
<span class="line" id="L21"></span>
<span class="line" id="L22"><span class="tok-comment">/// `slice` returns the bytes that correspond to this grapheme cluster in `src`.</span></span>
<span class="line" id="L23"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">slice</span>(self: Grapheme, src: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) []<span class="tok-kw">const</span> <span class="tok-type">u8</span> {</span>
<span class="line" id="L24"> <span class="tok-kw">return</span> src[self.offset .. self.offset + self.len];</span>
<span class="line" id="L25">}</span>
<span class="line" id="L26"></span>
<span class="line" id="L27"><span class="tok-comment">/// `GraphemeIterator` iterates a sting of UTF-8 encoded bytes one grapheme cluster at-a-time.</span></span>
<span class="line" id="L28"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> GraphemeIterator = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L29"> buf: [<span class="tok-number">2</span>]?CodePoint = [_]?CodePoint{ <span class="tok-null">null</span>, <span class="tok-null">null</span> },</span>
<span class="line" id="L30"> cp_iter: CodePointIterator,</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L33"></span>
<span class="line" id="L34"> <span class="tok-comment">/// Assumes `src` is valid UTF-8.</span></span>
<span class="line" id="L35"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) Self {</span>
<span class="line" id="L36"> <span class="tok-kw">var</span> self = Self{ .cp_iter = CodePointIterator{ .bytes = str } };</span>
<span class="line" id="L37"> self.buf[<span class="tok-number">1</span>] = self.cp_iter.next();</span>
<span class="line" id="L38"></span>
<span class="line" id="L39"> <span class="tok-kw">return</span> self;</span>
<span class="line" id="L40"> }</span>
<span class="line" id="L41"></span>
<span class="line" id="L42"> <span class="tok-kw">fn</span> <span class="tok-fn">advance</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L43"> self.buf[<span class="tok-number">0</span>] = self.buf[<span class="tok-number">1</span>];</span>
<span class="line" id="L44"> self.buf[<span class="tok-number">1</span>] = self.cp_iter.next();</span>
<span class="line" id="L45"> }</span>
<span class="line" id="L46"></span>
<span class="line" id="L47"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">next</span>(self: *Self) ?Grapheme {</span>
<span class="line" id="L48"> self.advance();</span>
<span class="line" id="L49"></span>
<span class="line" id="L50"> <span class="tok-comment">// If at end</span>
</span>
<span class="line" id="L51"> <span class="tok-kw">if</span> (self.buf[<span class="tok-number">0</span>] == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L52"> <span class="tok-kw">if</span> (self.buf[<span class="tok-number">1</span>] == <span class="tok-null">null</span>) <span class="tok-kw">return</span> Grapheme{ .len = self.buf[<span class="tok-number">0</span>].?.len, .offset = self.buf[<span class="tok-number">0</span>].?.offset };</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-kw">const</span> gc_start = self.buf[<span class="tok-number">0</span>].?.offset;</span>
<span class="line" id="L55"> <span class="tok-kw">var</span> gc_len: <span class="tok-type">usize</span> = self.buf[<span class="tok-number">0</span>].?.len;</span>
<span class="line" id="L56"> <span class="tok-kw">var</span> state: <span class="tok-type">u3</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"> <span class="tok-kw">if</span> (graphemeBreak(</span>
<span class="line" id="L59"> self.buf[<span class="tok-number">0</span>].?.code,</span>
<span class="line" id="L60"> self.buf[<span class="tok-number">1</span>].?.code,</span>
<span class="line" id="L61"> &amp;state,</span>
<span class="line" id="L62"> )) <span class="tok-kw">return</span> Grapheme{ .len = gc_len, .offset = gc_start };</span>
<span class="line" id="L63"></span>
<span class="line" id="L64"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L65"> self.advance();</span>
<span class="line" id="L66"> <span class="tok-kw">if</span> (self.buf[<span class="tok-number">0</span>] == <span class="tok-null">null</span>) <span class="tok-kw">break</span>;</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"> gc_len += self.buf[<span class="tok-number">0</span>].?.len;</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"> <span class="tok-kw">if</span> (graphemeBreak(</span>
<span class="line" id="L71"> self.buf[<span class="tok-number">0</span>].?.code,</span>
<span class="line" id="L72"> <span class="tok-kw">if</span> (self.buf[<span class="tok-number">1</span>]) |ncp| ncp.code <span class="tok-kw">else</span> <span class="tok-number">0</span>,</span>
<span class="line" id="L73"> &amp;state,</span>
<span class="line" id="L74"> )) <span class="tok-kw">break</span>;</span>
<span class="line" id="L75"> }</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"> <span class="tok-kw">return</span> Grapheme{ .len = gc_len, .offset = gc_start };</span>
<span class="line" id="L78"> }</span>
<span class="line" id="L79">};</span>
<span class="line" id="L80"></span>
<span class="line" id="L81"><span class="tok-comment">/// `StreamingGraphemeIterator` iterates a `std.io.Reader` one grapheme cluster at-a-time.</span></span>
<span class="line" id="L82"><span class="tok-comment">/// Note that, given the steaming context, each grapheme cluster is returned as a slice of bytes.</span></span>
<span class="line" id="L83"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">StreamingGraphemeIterator</span>(<span class="tok-kw">comptime</span> T: <span class="tok-type">type</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L84"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L85"> allocator: std.mem.Allocator,</span>
<span class="line" id="L86"> buf: [<span class="tok-number">2</span>]?<span class="tok-type">u21</span> = [_]?<span class="tok-type">u21</span>{ <span class="tok-null">null</span>, <span class="tok-null">null</span> },</span>
<span class="line" id="L87"> reader: T,</span>
<span class="line" id="L88"></span>
<span class="line" id="L89"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L90"></span>
<span class="line" id="L91"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(allocator: std.mem.Allocator, reader: <span class="tok-kw">anytype</span>) !Self {</span>
<span class="line" id="L92"> <span class="tok-kw">var</span> self = Self{ .allocator = allocator, .reader = reader };</span>
<span class="line" id="L93"> self.buf[<span class="tok-number">1</span>] = <span class="tok-kw">try</span> readCodePoint(self.reader);</span>
<span class="line" id="L94"></span>
<span class="line" id="L95"> <span class="tok-kw">return</span> self;</span>
<span class="line" id="L96"> }</span>
<span class="line" id="L97"></span>
<span class="line" id="L98"> <span class="tok-comment">/// Caller must free returned bytes with `allocator` passed to `init`.</span></span>
<span class="line" id="L99"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">next</span>(self: *Self) !?[]<span class="tok-type">u8</span> {</span>
<span class="line" id="L100"> <span class="tok-kw">const</span> code = (<span class="tok-kw">try</span> self.advance()) <span class="tok-kw">orelse</span> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L101"></span>
<span class="line" id="L102"> <span class="tok-kw">var</span> all_bytes = std.ArrayList(<span class="tok-type">u8</span>).init(self.allocator);</span>
<span class="line" id="L103"> <span class="tok-kw">errdefer</span> all_bytes.deinit();</span>
<span class="line" id="L104"></span>
<span class="line" id="L105"> <span class="tok-kw">try</span> encode_and_append(code, &amp;all_bytes);</span>
<span class="line" id="L106"></span>
<span class="line" id="L107"> <span class="tok-comment">// If at end</span>
</span>
<span class="line" id="L108"> <span class="tok-kw">if</span> (self.buf[<span class="tok-number">1</span>] == <span class="tok-null">null</span>) <span class="tok-kw">return</span> <span class="tok-kw">try</span> all_bytes.toOwnedSlice();</span>
<span class="line" id="L109"></span>
<span class="line" id="L110"> <span class="tok-comment">// Instant breakers</span>
</span>
<span class="line" id="L111"> <span class="tok-comment">// CR</span>
</span>
<span class="line" id="L112"> <span class="tok-kw">if</span> (code == <span class="tok-str">'\x0d'</span>) {</span>
<span class="line" id="L113"> <span class="tok-kw">if</span> (self.buf[<span class="tok-number">1</span>].? == <span class="tok-str">'\x0a'</span>) {</span>
<span class="line" id="L114"> <span class="tok-comment">// CRLF</span>
</span>
<span class="line" id="L115"> <span class="tok-kw">try</span> encode_and_append(self.buf[<span class="tok-number">1</span>].?, &amp;all_bytes);</span>
<span class="line" id="L116"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L117"> }</span>
<span class="line" id="L118"></span>
<span class="line" id="L119"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> all_bytes.toOwnedSlice();</span>
<span class="line" id="L120"> }</span>
<span class="line" id="L121"> <span class="tok-comment">// LF</span>
</span>
<span class="line" id="L122"> <span class="tok-kw">if</span> (code == <span class="tok-str">'\x0a'</span>) <span class="tok-kw">return</span> <span class="tok-kw">try</span> all_bytes.toOwnedSlice();</span>
<span class="line" id="L123"> <span class="tok-comment">// Control</span>
</span>
<span class="line" id="L124"> <span class="tok-kw">if</span> (gbp.isControl(code)) <span class="tok-kw">return</span> <span class="tok-kw">try</span> all_bytes.toOwnedSlice();</span>
<span class="line" id="L125"></span>
<span class="line" id="L126"> <span class="tok-comment">// Common chars</span>
</span>
<span class="line" id="L127"> <span class="tok-kw">if</span> (code &lt; <span class="tok-number">0xa9</span>) {</span>
<span class="line" id="L128"> <span class="tok-comment">// Extend / ignorables loop</span>
</span>
<span class="line" id="L129"> <span class="tok-kw">while</span> (self.buf[<span class="tok-number">1</span>]) |next_cp| {</span>
<span class="line" id="L130"> <span class="tok-kw">if</span> (next_cp &gt;= <span class="tok-number">0x300</span> <span class="tok-kw">and</span> isIgnorable(next_cp)) {</span>
<span class="line" id="L131"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L132"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L133"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L134"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L135"> }</span>
<span class="line" id="L136"> }</span>
<span class="line" id="L137"></span>
<span class="line" id="L138"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> all_bytes.toOwnedSlice();</span>
<span class="line" id="L139"> }</span>
<span class="line" id="L140"></span>
<span class="line" id="L141"> <span class="tok-kw">if</span> (emoji.isExtendedPictographic(code)) {</span>
<span class="line" id="L142"> <span class="tok-kw">var</span> after_zwj = <span class="tok-null">false</span>;</span>
<span class="line" id="L143"></span>
<span class="line" id="L144"> <span class="tok-comment">// Extend / ignorables loop</span>
</span>
<span class="line" id="L145"> <span class="tok-kw">while</span> (self.buf[<span class="tok-number">1</span>]) |next_cp| {</span>
<span class="line" id="L146"> <span class="tok-kw">if</span> (next_cp &gt;= <span class="tok-number">0x300</span> <span class="tok-kw">and</span></span>
<span class="line" id="L147"> after_zwj <span class="tok-kw">and</span></span>
<span class="line" id="L148"> emoji.isExtendedPictographic(next_cp))</span>
<span class="line" id="L149"> {</span>
<span class="line" id="L150"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L151"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L152"> after_zwj = <span class="tok-null">false</span>;</span>
<span class="line" id="L153"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (next_cp &gt;= <span class="tok-number">0x300</span> <span class="tok-kw">and</span> isIgnorable(next_cp)) {</span>
<span class="line" id="L154"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L155"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L156"> <span class="tok-kw">if</span> (next_cp == <span class="tok-str">'\u{200d}'</span>) after_zwj = <span class="tok-null">true</span>;</span>
<span class="line" id="L157"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L158"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L159"> }</span>
<span class="line" id="L160"> }</span>
<span class="line" id="L161"></span>
<span class="line" id="L162"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> all_bytes.toOwnedSlice();</span>
<span class="line" id="L163"> }</span>
<span class="line" id="L164"></span>
<span class="line" id="L165"> <span class="tok-kw">if</span> (<span class="tok-number">0x1100</span> &lt;= code <span class="tok-kw">and</span> code &lt;= <span class="tok-number">0xd7c6</span>) {</span>
<span class="line" id="L166"> <span class="tok-kw">const</span> next_cp = self.buf[<span class="tok-number">1</span>].?;</span>
<span class="line" id="L167"></span>
<span class="line" id="L168"> <span class="tok-kw">if</span> (gbp.isL(code)) {</span>
<span class="line" id="L169"> <span class="tok-kw">if</span> (next_cp &gt;= <span class="tok-number">0x1100</span> <span class="tok-kw">and</span></span>
<span class="line" id="L170"> (gbp.isL(next_cp) <span class="tok-kw">or</span></span>
<span class="line" id="L171"> gbp.isV(next_cp) <span class="tok-kw">or</span></span>
<span class="line" id="L172"> gbp.isLv(next_cp) <span class="tok-kw">or</span></span>
<span class="line" id="L173"> gbp.isLvt(next_cp)))</span>
<span class="line" id="L174"> {</span>
<span class="line" id="L175"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L176"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L177"> }</span>
<span class="line" id="L178"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (gbp.isLv(code) <span class="tok-kw">or</span> gbp.isV(code)) {</span>
<span class="line" id="L179"> <span class="tok-kw">if</span> (next_cp &gt;= <span class="tok-number">0x1100</span> <span class="tok-kw">and</span></span>
<span class="line" id="L180"> (gbp.isV(next_cp) <span class="tok-kw">or</span></span>
<span class="line" id="L181"> gbp.isT(next_cp)))</span>
<span class="line" id="L182"> {</span>
<span class="line" id="L183"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L184"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L185"> }</span>
<span class="line" id="L186"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (gbp.isLvt(code) <span class="tok-kw">or</span> gbp.isT(code)) {</span>
<span class="line" id="L187"> <span class="tok-kw">if</span> (next_cp &gt;= <span class="tok-number">0x1100</span> <span class="tok-kw">and</span> gbp.isT(next_cp)) {</span>
<span class="line" id="L188"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L189"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L190"> }</span>
<span class="line" id="L191"> }</span>
<span class="line" id="L192"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (<span class="tok-number">0x600</span> &lt;= code <span class="tok-kw">and</span> code &lt;= <span class="tok-number">0x11f02</span>) {</span>
<span class="line" id="L193"> <span class="tok-kw">if</span> (gbp.isPrepend(code)) {</span>
<span class="line" id="L194"> <span class="tok-kw">const</span> next_cp = self.buf[<span class="tok-number">1</span>].?;</span>
<span class="line" id="L195"></span>
<span class="line" id="L196"> <span class="tok-kw">if</span> (isBreaker(next_cp)) {</span>
<span class="line" id="L197"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> all_bytes.toOwnedSlice();</span>
<span class="line" id="L198"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L199"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L200"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L201"> }</span>
<span class="line" id="L202"> }</span>
<span class="line" id="L203"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (<span class="tok-number">0x1f1e6</span> &lt;= code <span class="tok-kw">and</span> code &lt;= <span class="tok-number">0x1f1ff</span>) {</span>
<span class="line" id="L204"> <span class="tok-kw">if</span> (gbp.isRegionalIndicator(code)) {</span>
<span class="line" id="L205"> <span class="tok-kw">const</span> next_cp = self.buf[<span class="tok-number">1</span>].?;</span>
<span class="line" id="L206"></span>
<span class="line" id="L207"> <span class="tok-kw">if</span> (next_cp &gt;= <span class="tok-number">0x1f1e6</span> <span class="tok-kw">and</span> gbp.isRegionalIndicator(next_cp)) {</span>
<span class="line" id="L208"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L209"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L210"> }</span>
<span class="line" id="L211"> }</span>
<span class="line" id="L212"> }</span>
<span class="line" id="L213"></span>
<span class="line" id="L214"> <span class="tok-comment">// Extend / ignorables loop</span>
</span>
<span class="line" id="L215"> <span class="tok-kw">while</span> (self.buf[<span class="tok-number">1</span>]) |next_cp| {</span>
<span class="line" id="L216"> <span class="tok-kw">if</span> (next_cp &gt;= <span class="tok-number">0x300</span> <span class="tok-kw">and</span> isIgnorable(next_cp)) {</span>
<span class="line" id="L217"> <span class="tok-kw">try</span> encode_and_append(next_cp, &amp;all_bytes);</span>
<span class="line" id="L218"> _ = self.advance() <span class="tok-kw">catch</span> <span class="tok-kw">unreachable</span>;</span>
<span class="line" id="L219"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L220"> <span class="tok-kw">break</span>;</span>
<span class="line" id="L221"> }</span>
<span class="line" id="L222"> }</span>
<span class="line" id="L223"></span>
<span class="line" id="L224"> <span class="tok-kw">return</span> <span class="tok-kw">try</span> all_bytes.toOwnedSlice();</span>
<span class="line" id="L225"> }</span>
<span class="line" id="L226"></span>
<span class="line" id="L227"> <span class="tok-kw">fn</span> <span class="tok-fn">advance</span>(self: *Self) !?<span class="tok-type">u21</span> {</span>
<span class="line" id="L228"> self.buf[<span class="tok-number">0</span>] = self.buf[<span class="tok-number">1</span>];</span>
<span class="line" id="L229"> self.buf[<span class="tok-number">1</span>] = <span class="tok-kw">try</span> readCodePoint(self.reader);</span>
<span class="line" id="L230"></span>
<span class="line" id="L231"> <span class="tok-kw">return</span> self.buf[<span class="tok-number">0</span>];</span>
<span class="line" id="L232"> }</span>
<span class="line" id="L233"></span>
<span class="line" id="L234"> <span class="tok-kw">fn</span> <span class="tok-fn">peek</span>(self: Self) ?<span class="tok-type">u21</span> {</span>
<span class="line" id="L235"> <span class="tok-kw">return</span> self.buf[<span class="tok-number">1</span>];</span>
<span class="line" id="L236"> }</span>
<span class="line" id="L237"></span>
<span class="line" id="L238"> <span class="tok-kw">fn</span> <span class="tok-fn">encode_and_append</span>(cp: <span class="tok-type">u21</span>, list: *std.ArrayList(<span class="tok-type">u8</span>)) !<span class="tok-type">void</span> {</span>
<span class="line" id="L239"> <span class="tok-kw">var</span> tmp: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L240"> <span class="tok-kw">const</span> len = <span class="tok-kw">try</span> unicode.utf8Encode(cp, &amp;tmp);</span>
<span class="line" id="L241"> <span class="tok-kw">try</span> list.appendSlice(tmp[<span class="tok-number">0</span>..len]);</span>
<span class="line" id="L242"> }</span>
<span class="line" id="L243"> };</span>
<span class="line" id="L244">}</span>
<span class="line" id="L245"></span>
<span class="line" id="L246"><span class="tok-comment">// Predicates</span>
</span>
<span class="line" id="L247"><span class="tok-kw">fn</span> <span class="tok-fn">isBreaker</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L248"> <span class="tok-kw">return</span> cp == <span class="tok-str">'\x0d'</span> <span class="tok-kw">or</span> cp == <span class="tok-str">'\x0a'</span> <span class="tok-kw">or</span> gbp.isControl(cp);</span>
<span class="line" id="L249">}</span>
<span class="line" id="L250"></span>
<span class="line" id="L251"><span class="tok-kw">fn</span> <span class="tok-fn">isIgnorable</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L252"> <span class="tok-kw">return</span> gbp.isExtend(cp) <span class="tok-kw">or</span> gbp.isSpacingmark(cp) <span class="tok-kw">or</span> cp == <span class="tok-str">'\u{200d}'</span>;</span>
<span class="line" id="L253">}</span>
<span class="line" id="L254"></span>
<span class="line" id="L255"><span class="tok-kw">test</span> <span class="tok-str">&quot;Segmentation comptime GraphemeIterator&quot;</span> {</span>
<span class="line" id="L256"> <span class="tok-kw">const</span> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;H&quot;</span>, <span class="tok-str">&quot;é&quot;</span>, <span class="tok-str">&quot;l&quot;</span>, <span class="tok-str">&quot;l&quot;</span>, <span class="tok-str">&quot;o&quot;</span> };</span>
<span class="line" id="L257"></span>
<span class="line" id="L258"> <span class="tok-kw">comptime</span> {</span>
<span class="line" id="L259"> <span class="tok-kw">const</span> src = <span class="tok-str">&quot;Héllo&quot;</span>;</span>
<span class="line" id="L260"> <span class="tok-kw">var</span> ct_iter = GraphemeIterator.init(src);</span>
<span class="line" id="L261"> <span class="tok-kw">var</span> i = <span class="tok-number">0</span>;</span>
<span class="line" id="L262"> <span class="tok-kw">while</span> (ct_iter.next()) |grapheme| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L263"> <span class="tok-kw">try</span> std.testing.expect(grapheme.eql(src, want[i]));</span>
<span class="line" id="L264"> }</span>
<span class="line" id="L265"> }</span>
<span class="line" id="L266">}</span>
<span class="line" id="L267"></span>
<span class="line" id="L268"><span class="tok-kw">test</span> <span class="tok-str">&quot;Simple StreamingGraphemeIterator&quot;</span> {</span>
<span class="line" id="L269"> <span class="tok-kw">var</span> buf = <span class="tok-str">&quot;abe\u{301}😹&quot;</span>.*;</span>
<span class="line" id="L270"> <span class="tok-kw">var</span> fis = std.io.fixedBufferStream(&amp;buf);</span>
<span class="line" id="L271"> <span class="tok-kw">const</span> reader = fis.reader();</span>
<span class="line" id="L272"> <span class="tok-kw">var</span> iter = <span class="tok-kw">try</span> StreamingGraphemeIterator(<span class="tok-builtin">@TypeOf</span>(reader)).init(std.testing.allocator, reader);</span>
<span class="line" id="L273"> <span class="tok-kw">const</span> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;a&quot;</span>, <span class="tok-str">&quot;b&quot;</span>, <span class="tok-str">&quot;e\u{301}&quot;</span>, <span class="tok-str">&quot;😹&quot;</span> };</span>
<span class="line" id="L274"></span>
<span class="line" id="L275"> <span class="tok-kw">for</span> (want) |str| {</span>
<span class="line" id="L276"> <span class="tok-kw">const</span> gc = (<span class="tok-kw">try</span> iter.next()).?;</span>
<span class="line" id="L277"> <span class="tok-kw">defer</span> std.testing.allocator.free(gc);</span>
<span class="line" id="L278"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(gc, str);</span>
<span class="line" id="L279"> }</span>
<span class="line" id="L280"></span>
<span class="line" id="L281"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(?[]<span class="tok-type">u8</span>, <span class="tok-null">null</span>), <span class="tok-kw">try</span> iter.next());</span>
<span class="line" id="L282">}</span>
<span class="line" id="L283"></span>
<span class="line" id="L284"><span class="tok-kw">test</span> <span class="tok-str">&quot;Segmentation ZWJ and ZWSP emoji sequences&quot;</span> {</span>
<span class="line" id="L285"> <span class="tok-kw">const</span> seq_1 = <span class="tok-str">&quot;\u{1F43B}\u{200D}\u{2744}\u{FE0F}&quot;</span>;</span>
<span class="line" id="L286"> <span class="tok-kw">const</span> seq_2 = <span class="tok-str">&quot;\u{1F43B}\u{200D}\u{2744}\u{FE0F}&quot;</span>;</span>
<span class="line" id="L287"> <span class="tok-kw">const</span> with_zwj = seq_1 ++ <span class="tok-str">&quot;\u{200D}&quot;</span> ++ seq_2;</span>
<span class="line" id="L288"> <span class="tok-kw">const</span> with_zwsp = seq_1 ++ <span class="tok-str">&quot;\u{200B}&quot;</span> ++ seq_2;</span>
<span class="line" id="L289"> <span class="tok-kw">const</span> no_joiner = seq_1 ++ seq_2;</span>
<span class="line" id="L290"></span>
<span class="line" id="L291"> <span class="tok-kw">var</span> ct_iter = GraphemeIterator.init(with_zwj);</span>
<span class="line" id="L292"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L293"> <span class="tok-kw">while</span> (ct_iter.next()) |_| : (i += <span class="tok-number">1</span>) {}</span>
<span class="line" id="L294"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">1</span>), i);</span>
<span class="line" id="L295"></span>
<span class="line" id="L296"> ct_iter = GraphemeIterator.init(with_zwsp);</span>
<span class="line" id="L297"> i = <span class="tok-number">0</span>;</span>
<span class="line" id="L298"> <span class="tok-kw">while</span> (ct_iter.next()) |_| : (i += <span class="tok-number">1</span>) {}</span>
<span class="line" id="L299"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">3</span>), i);</span>
<span class="line" id="L300"></span>
<span class="line" id="L301"> ct_iter = GraphemeIterator.init(no_joiner);</span>
<span class="line" id="L302"> i = <span class="tok-number">0</span>;</span>
<span class="line" id="L303"> <span class="tok-kw">while</span> (ct_iter.next()) |_| : (i += <span class="tok-number">1</span>) {}</span>
<span class="line" id="L304"> <span class="tok-kw">try</span> std.testing.expectEqual(<span class="tok-builtin">@as</span>(<span class="tok-type">usize</span>, <span class="tok-number">2</span>), i);</span>
<span class="line" id="L305">}</span>
<span class="line" id="L306"></span>
<span class="line" id="L307"><span class="tok-comment">// Grapheme break state.</span>
</span>
<span class="line" id="L308"><span class="tok-kw">fn</span> <span class="tok-fn">hasXpic</span>(state: *<span class="tok-kw">const</span> <span class="tok-type">u3</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L309"> <span class="tok-kw">return</span> state.* &amp; <span class="tok-number">1</span> == <span class="tok-number">1</span>;</span>
<span class="line" id="L310">}</span>
<span class="line" id="L311"></span>
<span class="line" id="L312"><span class="tok-kw">fn</span> <span class="tok-fn">setXpic</span>(state: *<span class="tok-type">u3</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L313"> state.* |= <span class="tok-number">1</span>;</span>
<span class="line" id="L314">}</span>
<span class="line" id="L315"></span>
<span class="line" id="L316"><span class="tok-kw">fn</span> <span class="tok-fn">unsetXpic</span>(state: *<span class="tok-type">u3</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L317"> state.* ^= <span class="tok-number">1</span>;</span>
<span class="line" id="L318">}</span>
<span class="line" id="L319"></span>
<span class="line" id="L320"><span class="tok-kw">fn</span> <span class="tok-fn">hasRegional</span>(state: *<span class="tok-kw">const</span> <span class="tok-type">u3</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L321"> <span class="tok-kw">return</span> state.* &amp; <span class="tok-number">2</span> == <span class="tok-number">2</span>;</span>
<span class="line" id="L322">}</span>
<span class="line" id="L323"></span>
<span class="line" id="L324"><span class="tok-kw">fn</span> <span class="tok-fn">setRegional</span>(state: *<span class="tok-type">u3</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L325"> state.* |= <span class="tok-number">2</span>;</span>
<span class="line" id="L326">}</span>
<span class="line" id="L327"></span>
<span class="line" id="L328"><span class="tok-kw">fn</span> <span class="tok-fn">unsetRegional</span>(state: *<span class="tok-type">u3</span>) <span class="tok-type">void</span> {</span>
<span class="line" id="L329"> state.* ^= <span class="tok-number">2</span>;</span>
<span class="line" id="L330">}</span>
<span class="line" id="L331"></span>
<span class="line" id="L332"><span class="tok-comment">/// `graphemeBreak` returns true only if a grapheme break point is required</span></span>
<span class="line" id="L333"><span class="tok-comment">/// between `cp1` and `cp2`. `state` should start out as 0. If calling</span></span>
<span class="line" id="L334"><span class="tok-comment">/// iteratively over a sequence of code points, this function must be called</span></span>
<span class="line" id="L335"><span class="tok-comment">/// IN ORDER on ALL potential breaks in a string.</span></span>
<span class="line" id="L336"><span class="tok-comment">/// Modeled after the API of utf8proc's `utf8proc_grapheme_break_stateful`.</span></span>
<span class="line" id="L337"><span class="tok-comment">/// https://github.com/JuliaStrings/utf8proc/blob/2bbb1ba932f727aad1fab14fafdbc89ff9dc4604/utf8proc.h#L599-L617</span></span>
<span class="line" id="L338"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">graphemeBreak</span>(</span>
<span class="line" id="L339"> cp1: <span class="tok-type">u21</span>,</span>
<span class="line" id="L340"> cp2: <span class="tok-type">u21</span>,</span>
<span class="line" id="L341"> state: *<span class="tok-type">u3</span>,</span>
<span class="line" id="L342">) <span class="tok-type">bool</span> {</span>
<span class="line" id="L343"> <span class="tok-comment">// GB11: Emoji Extend* ZWJ x Emoji</span>
</span>
<span class="line" id="L344"> <span class="tok-kw">if</span> (!hasXpic(state) <span class="tok-kw">and</span> emoji.isExtendedPictographic(cp1)) setXpic(state);</span>
<span class="line" id="L345"></span>
<span class="line" id="L346"> <span class="tok-comment">// GB3: CR x LF</span>
</span>
<span class="line" id="L347"> <span class="tok-kw">if</span> (cp1 == <span class="tok-str">'\r'</span> <span class="tok-kw">and</span> cp2 == <span class="tok-str">'\n'</span>) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L348"></span>
<span class="line" id="L349"> <span class="tok-comment">// GB4: Control</span>
</span>
<span class="line" id="L350"> <span class="tok-kw">if</span> (isBreaker(cp1)) <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L351"></span>
<span class="line" id="L352"> <span class="tok-comment">// GB6: Hangul L x (L|V|LV|VT)</span>
</span>
<span class="line" id="L353"> <span class="tok-kw">if</span> (gbp.isL(cp1)) {</span>
<span class="line" id="L354"> <span class="tok-kw">if</span> (gbp.isL(cp2) <span class="tok-kw">or</span></span>
<span class="line" id="L355"> gbp.isV(cp2) <span class="tok-kw">or</span></span>
<span class="line" id="L356"> gbp.isLv(cp2) <span class="tok-kw">or</span></span>
<span class="line" id="L357"> gbp.isLvt(cp2)) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L358"> }</span>
<span class="line" id="L359"></span>
<span class="line" id="L360"> <span class="tok-comment">// GB7: Hangul (LV | V) x (V | T)</span>
</span>
<span class="line" id="L361"> <span class="tok-kw">if</span> (gbp.isLv(cp1) <span class="tok-kw">or</span> gbp.isV(cp1)) {</span>
<span class="line" id="L362"> <span class="tok-kw">if</span> (gbp.isV(cp2) <span class="tok-kw">or</span></span>
<span class="line" id="L363"> gbp.isT(cp2)) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L364"> }</span>
<span class="line" id="L365"></span>
<span class="line" id="L366"> <span class="tok-comment">// GB8: Hangul (LVT | T) x T</span>
</span>
<span class="line" id="L367"> <span class="tok-kw">if</span> (gbp.isLvt(cp1) <span class="tok-kw">or</span> gbp.isT(cp1)) {</span>
<span class="line" id="L368"> <span class="tok-kw">if</span> (gbp.isT(cp2)) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L369"> }</span>
<span class="line" id="L370"></span>
<span class="line" id="L371"> <span class="tok-comment">// GB9b: x (Extend | ZWJ)</span>
</span>
<span class="line" id="L372"> <span class="tok-kw">if</span> (gbp.isExtend(cp2) <span class="tok-kw">or</span> gbp.isZwj(cp2)) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L373"></span>
<span class="line" id="L374"> <span class="tok-comment">// GB9a: x Spacing</span>
</span>
<span class="line" id="L375"> <span class="tok-kw">if</span> (gbp.isSpacingmark(cp2)) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L376"></span>
<span class="line" id="L377"> <span class="tok-comment">// GB9b: Prepend x</span>
</span>
<span class="line" id="L378"> <span class="tok-kw">if</span> (gbp.isPrepend(cp1) <span class="tok-kw">and</span> !isBreaker(cp2)) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L379"></span>
<span class="line" id="L380"> <span class="tok-comment">// GB12, GB13: RI x RI</span>
</span>
<span class="line" id="L381"> <span class="tok-kw">if</span> (gbp.isRegionalIndicator(cp1) <span class="tok-kw">and</span> gbp.isRegionalIndicator(cp2)) {</span>
<span class="line" id="L382"> <span class="tok-kw">if</span> (hasRegional(state)) {</span>
<span class="line" id="L383"> unsetRegional(state);</span>
<span class="line" id="L384"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L385"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L386"> setRegional(state);</span>
<span class="line" id="L387"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L388"> }</span>
<span class="line" id="L389"> }</span>
<span class="line" id="L390"></span>
<span class="line" id="L391"> <span class="tok-comment">// GB11: Emoji Extend* ZWJ x Emoji</span>
</span>
<span class="line" id="L392"> <span class="tok-kw">if</span> (hasXpic(state) <span class="tok-kw">and</span></span>
<span class="line" id="L393"> gbp.isZwj(cp1) <span class="tok-kw">and</span></span>
<span class="line" id="L394"> emoji.isExtendedPictographic(cp2))</span>
<span class="line" id="L395"> {</span>
<span class="line" id="L396"> unsetXpic(state);</span>
<span class="line" id="L397"> <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L398"> }</span>
<span class="line" id="L399"></span>
<span class="line" id="L400"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L401">}</span>
<span class="line" id="L402"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,847 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>segmenter/Sentence.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `Sentence` represents a sentence within a UTF-8 encoded string.</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> unicode = std.unicode;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> sbp = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/sentence_break_property.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> CodePoint = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;CodePoint.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> CodePointIterator = CodePoint.CodePointIterator;</span>
<span class="line" id="L9"></span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Sentence = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L11"></span>
<span class="line" id="L12">bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L13">offset: <span class="tok-type">usize</span>,</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-comment">/// `eql` compares `str` with the bytes of this sentence for equality.</span></span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eql</span>(self: Sentence, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L17"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, self.bytes, str);</span>
<span class="line" id="L18">}</span>
<span class="line" id="L19"></span>
<span class="line" id="L20"><span class="tok-kw">const</span> Type = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L21"> aterm,</span>
<span class="line" id="L22"> close,</span>
<span class="line" id="L23"> cr,</span>
<span class="line" id="L24"> extend,</span>
<span class="line" id="L25"> format,</span>
<span class="line" id="L26"> lf,</span>
<span class="line" id="L27"> lower,</span>
<span class="line" id="L28"> numeric,</span>
<span class="line" id="L29"> oletter,</span>
<span class="line" id="L30"> scontinue,</span>
<span class="line" id="L31"> sep,</span>
<span class="line" id="L32"> sp,</span>
<span class="line" id="L33"> sterm,</span>
<span class="line" id="L34"> upper,</span>
<span class="line" id="L35"> any,</span>
<span class="line" id="L36"></span>
<span class="line" id="L37"> <span class="tok-kw">fn</span> <span class="tok-fn">get</span>(cp: CodePoint) Type {</span>
<span class="line" id="L38"> <span class="tok-kw">var</span> ty: Type = .any;</span>
<span class="line" id="L39"> <span class="tok-kw">if</span> (<span class="tok-number">0x000D</span> == cp.code) ty = .cr;</span>
<span class="line" id="L40"> <span class="tok-kw">if</span> (<span class="tok-number">0x000A</span> == cp.code) ty = .lf;</span>
<span class="line" id="L41"> <span class="tok-kw">if</span> (sbp.isLower(cp.code)) ty = .lower;</span>
<span class="line" id="L42"> <span class="tok-kw">if</span> (sbp.isUpper(cp.code)) ty = .upper;</span>
<span class="line" id="L43"> <span class="tok-kw">if</span> (sbp.isOletter(cp.code)) ty = .oletter;</span>
<span class="line" id="L44"> <span class="tok-kw">if</span> (sbp.isNumeric(cp.code)) ty = .numeric;</span>
<span class="line" id="L45"> <span class="tok-kw">if</span> (sbp.isSep(cp.code)) ty = .sep;</span>
<span class="line" id="L46"> <span class="tok-kw">if</span> (sbp.isSp(cp.code)) ty = .sp;</span>
<span class="line" id="L47"> <span class="tok-kw">if</span> (sbp.isClose(cp.code)) ty = .close;</span>
<span class="line" id="L48"> <span class="tok-kw">if</span> (sbp.isAterm(cp.code)) ty = .aterm;</span>
<span class="line" id="L49"> <span class="tok-kw">if</span> (sbp.isSterm(cp.code)) ty = .sterm;</span>
<span class="line" id="L50"> <span class="tok-kw">if</span> (sbp.isScontinue(cp.code)) ty = .scontinue;</span>
<span class="line" id="L51"> <span class="tok-kw">if</span> (sbp.isExtend(cp.code)) ty = .extend;</span>
<span class="line" id="L52"> <span class="tok-kw">if</span> (sbp.isFormat(cp.code)) ty = .format;</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"> <span class="tok-kw">return</span> ty;</span>
<span class="line" id="L55"> }</span>
<span class="line" id="L56">};</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"><span class="tok-kw">const</span> Token = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L59"> ty: Type,</span>
<span class="line" id="L60"> code_point: CodePoint,</span>
<span class="line" id="L61"> offset: <span class="tok-type">usize</span> = <span class="tok-number">0</span>,</span>
<span class="line" id="L62"></span>
<span class="line" id="L63"> <span class="tok-kw">fn</span> <span class="tok-fn">is</span>(self: Token, ty: Type) <span class="tok-type">bool</span> {</span>
<span class="line" id="L64"> <span class="tok-kw">return</span> self.ty == ty;</span>
<span class="line" id="L65"> }</span>
<span class="line" id="L66">};</span>
<span class="line" id="L67"></span>
<span class="line" id="L68"><span class="tok-kw">const</span> TokenList = std.ArrayList(Token);</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"><span class="tok-comment">/// `SentenceIterator` iterates a string one sentence at-a-time.</span></span>
<span class="line" id="L71"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> SentenceIterator = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L72"> bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L73"> i: ?<span class="tok-type">usize</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L74"> start: ?Token = <span class="tok-null">null</span>,</span>
<span class="line" id="L75"> tokens: TokenList,</span>
<span class="line" id="L76"></span>
<span class="line" id="L77"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L78"></span>
<span class="line" id="L79"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !Self {</span>
<span class="line" id="L80"> <span class="tok-kw">if</span> (!unicode.utf8ValidateSlice(str)) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidUtf8;</span>
<span class="line" id="L81"></span>
<span class="line" id="L82"> <span class="tok-kw">var</span> self = Self{</span>
<span class="line" id="L83"> .bytes = str,</span>
<span class="line" id="L84"> .tokens = TokenList.init(allocator),</span>
<span class="line" id="L85"> };</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-kw">try</span> self.lex();</span>
<span class="line" id="L88"></span>
<span class="line" id="L89"> <span class="tok-kw">if</span> (self.tokens.items.len == <span class="tok-number">0</span>) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.NoTokens;</span>
<span class="line" id="L90"> self.start = self.tokens.items[<span class="tok-number">0</span>];</span>
<span class="line" id="L91"></span>
<span class="line" id="L92"> <span class="tok-comment">// Set token offsets.</span>
</span>
<span class="line" id="L93"> <span class="tok-kw">for</span> (self.tokens.items, <span class="tok-number">0</span>..) |*token, i| {</span>
<span class="line" id="L94"> token.offset = i;</span>
<span class="line" id="L95"> }</span>
<span class="line" id="L96"></span>
<span class="line" id="L97"> <span class="tok-kw">return</span> self;</span>
<span class="line" id="L98"> }</span>
<span class="line" id="L99"></span>
<span class="line" id="L100"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">deinit</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L101"> self.tokens.deinit();</span>
<span class="line" id="L102"> }</span>
<span class="line" id="L103"></span>
<span class="line" id="L104"> <span class="tok-kw">fn</span> <span class="tok-fn">lex</span>(self: *Self) !<span class="tok-type">void</span> {</span>
<span class="line" id="L105"> <span class="tok-kw">var</span> iter = CodePointIterator{</span>
<span class="line" id="L106"> .bytes = self.bytes,</span>
<span class="line" id="L107"> .i = <span class="tok-number">0</span>,</span>
<span class="line" id="L108"> };</span>
<span class="line" id="L109"></span>
<span class="line" id="L110"> <span class="tok-kw">while</span> (iter.next()) |cp| {</span>
<span class="line" id="L111"> <span class="tok-kw">try</span> self.tokens.append(.{</span>
<span class="line" id="L112"> .ty = Type.get(cp),</span>
<span class="line" id="L113"> .code_point = cp,</span>
<span class="line" id="L114"> });</span>
<span class="line" id="L115"> }</span>
<span class="line" id="L116"> }</span>
<span class="line" id="L117"></span>
<span class="line" id="L118"> <span class="tok-comment">// Main API.</span>
</span>
<span class="line" id="L119"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">next</span>(self: *Self) ?Sentence {</span>
<span class="line" id="L120"> no_break: <span class="tok-kw">while</span> (self.advance()) |current_token| {</span>
<span class="line" id="L121"> <span class="tok-kw">if</span> (isParaSep(current_token)) {</span>
<span class="line" id="L122"> <span class="tok-kw">var</span> end = current_token;</span>
<span class="line" id="L123"></span>
<span class="line" id="L124"> <span class="tok-kw">if</span> (current_token.is(.cr)) {</span>
<span class="line" id="L125"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L126"> <span class="tok-kw">if</span> (p.is(.lf)) {</span>
<span class="line" id="L127"> _ = self.advance();</span>
<span class="line" id="L128"> end = self.current();</span>
<span class="line" id="L129"> }</span>
<span class="line" id="L130"> }</span>
<span class="line" id="L131"> }</span>
<span class="line" id="L132"></span>
<span class="line" id="L133"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L134"> self.start = self.peek();</span>
<span class="line" id="L135"></span>
<span class="line" id="L136"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L137"> }</span>
<span class="line" id="L138"></span>
<span class="line" id="L139"> <span class="tok-kw">if</span> (current_token.is(.aterm)) {</span>
<span class="line" id="L140"> <span class="tok-kw">var</span> end = self.current();</span>
<span class="line" id="L141"></span>
<span class="line" id="L142"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L143"> <span class="tok-kw">if</span> (isUpper(p)) {</span>
<span class="line" id="L144"> <span class="tok-comment">// self.i may not be the same as current token's offset due to ignorable skipping.</span>
</span>
<span class="line" id="L145"> <span class="tok-kw">const</span> original_i = self.i;</span>
<span class="line" id="L146"> self.i = current_token.offset;</span>
<span class="line" id="L147"> <span class="tok-kw">defer</span> self.i = original_i;</span>
<span class="line" id="L148"></span>
<span class="line" id="L149"> <span class="tok-kw">if</span> (self.prevAfterSkip(isIgnorable)) |v| {</span>
<span class="line" id="L150"> <span class="tok-kw">if</span> (isUpperLower(v)) <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L151"> }</span>
<span class="line" id="L152"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isParaSep(p) <span class="tok-kw">or</span> isLower(p) <span class="tok-kw">or</span> isNumeric(p) <span class="tok-kw">or</span> isSContinue(p)) {</span>
<span class="line" id="L153"> <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L154"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isSpace(p)) {</span>
<span class="line" id="L155"> <span class="tok-comment">// ATerm Sp*</span>
</span>
<span class="line" id="L156"> self.run(isSpace);</span>
<span class="line" id="L157"> end = self.current();</span>
<span class="line" id="L158"> <span class="tok-comment">// Possible lower case after.</span>
</span>
<span class="line" id="L159"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L160"> <span class="tok-kw">if</span> (isLower(pp)) <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L161"> }</span>
<span class="line" id="L162"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isClose(p)) {</span>
<span class="line" id="L163"> <span class="tok-comment">// ATerm Close*</span>
</span>
<span class="line" id="L164"> self.run(isClose);</span>
<span class="line" id="L165"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L166"> <span class="tok-comment">// Possible ParaSep after.</span>
</span>
<span class="line" id="L167"> <span class="tok-kw">if</span> (isParaSep(pp)) {</span>
<span class="line" id="L168"> _ = self.advance();</span>
<span class="line" id="L169"> end = self.current();</span>
<span class="line" id="L170"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L171"> self.start = self.peek();</span>
<span class="line" id="L172"></span>
<span class="line" id="L173"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L174"> }</span>
<span class="line" id="L175"> <span class="tok-comment">// Possible spaces after.</span>
</span>
<span class="line" id="L176"> <span class="tok-kw">if</span> (isSpace(pp)) {</span>
<span class="line" id="L177"> <span class="tok-comment">// ATerm Close* Sp*</span>
</span>
<span class="line" id="L178"> self.run(isSpace);</span>
<span class="line" id="L179"></span>
<span class="line" id="L180"> <span class="tok-kw">if</span> (self.peek()) |ppp| {</span>
<span class="line" id="L181"> <span class="tok-comment">// Possible lower after.</span>
</span>
<span class="line" id="L182"> <span class="tok-kw">if</span> (isLower(ppp)) <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L183"> <span class="tok-comment">// Possible lower after some allowed code points.</span>
</span>
<span class="line" id="L184"> <span class="tok-kw">if</span> (isAllowedBeforeLower(ppp)) {</span>
<span class="line" id="L185"> <span class="tok-kw">if</span> (self.peekAfterSkip(isAllowedBeforeLower)) |pppp| {</span>
<span class="line" id="L186"> <span class="tok-comment">// ATerm Close* Sp* !(Unallowed) Lower</span>
</span>
<span class="line" id="L187"> <span class="tok-kw">if</span> (isLower(pppp)) <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L188"> }</span>
<span class="line" id="L189"> }</span>
<span class="line" id="L190"> }</span>
<span class="line" id="L191"> }</span>
<span class="line" id="L192"> }</span>
<span class="line" id="L193"></span>
<span class="line" id="L194"> end = self.current();</span>
<span class="line" id="L195"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isSATerm(p)) {</span>
<span class="line" id="L196"> self.run(isSATerm);</span>
<span class="line" id="L197"> end = self.current();</span>
<span class="line" id="L198"> }</span>
<span class="line" id="L199"> }</span>
<span class="line" id="L200"></span>
<span class="line" id="L201"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L202"> self.start = self.peek();</span>
<span class="line" id="L203"></span>
<span class="line" id="L204"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L205"> }</span>
<span class="line" id="L206"></span>
<span class="line" id="L207"> <span class="tok-kw">if</span> (current_token.is(.sterm)) {</span>
<span class="line" id="L208"> <span class="tok-kw">var</span> end = self.current();</span>
<span class="line" id="L209"></span>
<span class="line" id="L210"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L211"> <span class="tok-kw">if</span> (isParaSep(p) <span class="tok-kw">or</span> isSATerm(p) <span class="tok-kw">or</span> isSContinue(p)) {</span>
<span class="line" id="L212"> _ = self.advance();</span>
<span class="line" id="L213"> end = self.current();</span>
<span class="line" id="L214"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isSpace(p)) {</span>
<span class="line" id="L215"> self.run(isSpace);</span>
<span class="line" id="L216"> end = self.current();</span>
<span class="line" id="L217"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isClose(p)) {</span>
<span class="line" id="L218"> <span class="tok-comment">// STerm Close*</span>
</span>
<span class="line" id="L219"> self.run(isClose);</span>
<span class="line" id="L220"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L221"> <span class="tok-kw">if</span> (isSpace(pp)) {</span>
<span class="line" id="L222"> <span class="tok-comment">// STerm Close* Sp*</span>
</span>
<span class="line" id="L223"> self.run(isSpace);</span>
<span class="line" id="L224"> }</span>
<span class="line" id="L225"> }</span>
<span class="line" id="L226"></span>
<span class="line" id="L227"> end = self.current();</span>
<span class="line" id="L228"> }</span>
<span class="line" id="L229"> }</span>
<span class="line" id="L230"></span>
<span class="line" id="L231"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L232"> self.start = self.peek();</span>
<span class="line" id="L233"></span>
<span class="line" id="L234"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L235"> }</span>
<span class="line" id="L236"> }</span>
<span class="line" id="L237"></span>
<span class="line" id="L238"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (self.start) |start| self.emit(start, self.last()) <span class="tok-kw">else</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L239"> }</span>
<span class="line" id="L240"></span>
<span class="line" id="L241"> <span class="tok-comment">// Token array movement.</span>
</span>
<span class="line" id="L242"> <span class="tok-kw">fn</span> <span class="tok-fn">forward</span>(self: *Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L243"> <span class="tok-kw">if</span> (self.i) |*index| {</span>
<span class="line" id="L244"> index.* += <span class="tok-number">1</span>;</span>
<span class="line" id="L245"> <span class="tok-kw">if</span> (index.* &gt;= self.tokens.items.len) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L246"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L247"> self.i = <span class="tok-number">0</span>;</span>
<span class="line" id="L248"> }</span>
<span class="line" id="L249"></span>
<span class="line" id="L250"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L251"> }</span>
<span class="line" id="L252"></span>
<span class="line" id="L253"> <span class="tok-comment">// Token array movement.</span>
</span>
<span class="line" id="L254"> <span class="tok-kw">fn</span> <span class="tok-fn">getRelative</span>(self: Self, n: <span class="tok-type">isize</span>) ?Token {</span>
<span class="line" id="L255"> <span class="tok-kw">var</span> index: <span class="tok-type">usize</span> = self.i <span class="tok-kw">orelse</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L256"></span>
<span class="line" id="L257"> <span class="tok-kw">if</span> (n &lt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L258"> <span class="tok-kw">if</span> (index == <span class="tok-number">0</span> <span class="tok-kw">or</span> -%n &gt; index) <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L259"> index -= <span class="tok-builtin">@intCast</span>(-%n);</span>
<span class="line" id="L260"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L261"> <span class="tok-kw">const</span> un: <span class="tok-type">usize</span> = <span class="tok-builtin">@intCast</span>(n);</span>
<span class="line" id="L262"> <span class="tok-kw">if</span> (index + un &gt;= self.tokens.items.len) <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L263"> index += un;</span>
<span class="line" id="L264"> }</span>
<span class="line" id="L265"></span>
<span class="line" id="L266"> <span class="tok-kw">return</span> self.tokens.items[index];</span>
<span class="line" id="L267"> }</span>
<span class="line" id="L268"></span>
<span class="line" id="L269"> <span class="tok-kw">fn</span> <span class="tok-fn">prevAfterSkip</span>(self: *Self, predicate: TokenPredicate) ?Token {</span>
<span class="line" id="L270"> <span class="tok-kw">if</span> (self.i == <span class="tok-null">null</span> <span class="tok-kw">or</span> self.i.? == <span class="tok-number">0</span>) <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L271"></span>
<span class="line" id="L272"> <span class="tok-kw">var</span> i: <span class="tok-type">isize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L273"> <span class="tok-kw">while</span> (self.getRelative(-i)) |token| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L274"> <span class="tok-kw">if</span> (!predicate(token)) <span class="tok-kw">return</span> token;</span>
<span class="line" id="L275"> }</span>
<span class="line" id="L276"></span>
<span class="line" id="L277"> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L278"> }</span>
<span class="line" id="L279"></span>
<span class="line" id="L280"> <span class="tok-kw">fn</span> <span class="tok-fn">current</span>(self: Self) Token {</span>
<span class="line" id="L281"> <span class="tok-comment">// Assumes self.i is not null.</span>
</span>
<span class="line" id="L282"> <span class="tok-kw">return</span> self.tokens.items[self.i.?];</span>
<span class="line" id="L283"> }</span>
<span class="line" id="L284"></span>
<span class="line" id="L285"> <span class="tok-kw">fn</span> <span class="tok-fn">last</span>(self: Self) Token {</span>
<span class="line" id="L286"> <span class="tok-kw">return</span> self.tokens.items[self.tokens.items.len - <span class="tok-number">1</span>];</span>
<span class="line" id="L287"> }</span>
<span class="line" id="L288"></span>
<span class="line" id="L289"> <span class="tok-kw">fn</span> <span class="tok-fn">peek</span>(self: Self) ?Token {</span>
<span class="line" id="L290"> <span class="tok-kw">return</span> self.getRelative(<span class="tok-number">1</span>);</span>
<span class="line" id="L291"> }</span>
<span class="line" id="L292"></span>
<span class="line" id="L293"> <span class="tok-kw">fn</span> <span class="tok-fn">peekAfterSkip</span>(self: *Self, predicate: TokenPredicate) ?Token {</span>
<span class="line" id="L294"> <span class="tok-kw">var</span> i: <span class="tok-type">isize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L295"> <span class="tok-kw">while</span> (self.getRelative(i)) |token| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L296"> <span class="tok-kw">if</span> (!predicate(token)) <span class="tok-kw">return</span> token;</span>
<span class="line" id="L297"> }</span>
<span class="line" id="L298"></span>
<span class="line" id="L299"> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L300"> }</span>
<span class="line" id="L301"></span>
<span class="line" id="L302"> <span class="tok-kw">fn</span> <span class="tok-fn">advance</span>(self: *Self) ?Token {</span>
<span class="line" id="L303"> <span class="tok-kw">const</span> token = <span class="tok-kw">if</span> (self.forward()) self.current() <span class="tok-kw">else</span> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L304"> <span class="tok-kw">if</span> (!isParaSep(token)) _ = self.skipIgnorables(token);</span>
<span class="line" id="L305"></span>
<span class="line" id="L306"> <span class="tok-kw">return</span> token;</span>
<span class="line" id="L307"> }</span>
<span class="line" id="L308"></span>
<span class="line" id="L309"> <span class="tok-kw">fn</span> <span class="tok-fn">run</span>(self: *Self, predicate: TokenPredicate) <span class="tok-type">void</span> {</span>
<span class="line" id="L310"> <span class="tok-kw">while</span> (self.peek()) |token| {</span>
<span class="line" id="L311"> <span class="tok-kw">if</span> (!predicate(token)) <span class="tok-kw">break</span>;</span>
<span class="line" id="L312"> _ = self.advance();</span>
<span class="line" id="L313"> }</span>
<span class="line" id="L314"> }</span>
<span class="line" id="L315"></span>
<span class="line" id="L316"> <span class="tok-kw">fn</span> <span class="tok-fn">skipIgnorables</span>(self: *Self, end: Token) Token {</span>
<span class="line" id="L317"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L318"> <span class="tok-kw">if</span> (isIgnorable(p)) {</span>
<span class="line" id="L319"> self.run(isIgnorable);</span>
<span class="line" id="L320"> <span class="tok-kw">return</span> self.current();</span>
<span class="line" id="L321"> }</span>
<span class="line" id="L322"> }</span>
<span class="line" id="L323"></span>
<span class="line" id="L324"> <span class="tok-kw">return</span> end;</span>
<span class="line" id="L325"> }</span>
<span class="line" id="L326"></span>
<span class="line" id="L327"> <span class="tok-comment">// Production.</span>
</span>
<span class="line" id="L328"> <span class="tok-kw">fn</span> <span class="tok-fn">emit</span>(self: Self, start_token: Token, end_token: Token) Sentence {</span>
<span class="line" id="L329"> <span class="tok-kw">const</span> start = start_token.code_point.offset;</span>
<span class="line" id="L330"> <span class="tok-kw">const</span> end = end_token.code_point.offset + end_token.code_point.len;</span>
<span class="line" id="L331"></span>
<span class="line" id="L332"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L333"> .bytes = self.bytes[start..end],</span>
<span class="line" id="L334"> .offset = start,</span>
<span class="line" id="L335"> };</span>
<span class="line" id="L336"> }</span>
<span class="line" id="L337">};</span>
<span class="line" id="L338"></span>
<span class="line" id="L339"><span class="tok-comment">// Predicates</span>
</span>
<span class="line" id="L340"><span class="tok-kw">const</span> TokenPredicate = *<span class="tok-kw">const</span> <span class="tok-kw">fn</span> (Token) <span class="tok-type">bool</span>;</span>
<span class="line" id="L341"></span>
<span class="line" id="L342"><span class="tok-kw">fn</span> <span class="tok-fn">isNumeric</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L343"> <span class="tok-kw">return</span> token.ty == .numeric;</span>
<span class="line" id="L344">}</span>
<span class="line" id="L345"></span>
<span class="line" id="L346"><span class="tok-kw">fn</span> <span class="tok-fn">isLower</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L347"> <span class="tok-kw">return</span> token.ty == .lower;</span>
<span class="line" id="L348">}</span>
<span class="line" id="L349"></span>
<span class="line" id="L350"><span class="tok-kw">fn</span> <span class="tok-fn">isUpper</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L351"> <span class="tok-kw">return</span> token.ty == .upper;</span>
<span class="line" id="L352">}</span>
<span class="line" id="L353"></span>
<span class="line" id="L354"><span class="tok-kw">fn</span> <span class="tok-fn">isUpperLower</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L355"> <span class="tok-kw">return</span> isUpper(token) <span class="tok-kw">or</span> isLower(token);</span>
<span class="line" id="L356">}</span>
<span class="line" id="L357"></span>
<span class="line" id="L358"><span class="tok-kw">fn</span> <span class="tok-fn">isIgnorable</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L359"> <span class="tok-kw">return</span> token.ty == .extend <span class="tok-kw">or</span> token.ty == .format;</span>
<span class="line" id="L360">}</span>
<span class="line" id="L361"></span>
<span class="line" id="L362"><span class="tok-kw">fn</span> <span class="tok-fn">isClose</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L363"> <span class="tok-kw">return</span> token.ty == .close;</span>
<span class="line" id="L364">}</span>
<span class="line" id="L365"></span>
<span class="line" id="L366"><span class="tok-kw">fn</span> <span class="tok-fn">isSpace</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L367"> <span class="tok-kw">return</span> token.ty == .sp;</span>
<span class="line" id="L368">}</span>
<span class="line" id="L369"></span>
<span class="line" id="L370"><span class="tok-kw">fn</span> <span class="tok-fn">isParaSep</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L371"> <span class="tok-kw">return</span> token.ty == .cr <span class="tok-kw">or</span> token.ty == .lf <span class="tok-kw">or</span> token.ty == .sep;</span>
<span class="line" id="L372">}</span>
<span class="line" id="L373"></span>
<span class="line" id="L374"><span class="tok-kw">fn</span> <span class="tok-fn">isSATerm</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L375"> <span class="tok-kw">return</span> token.ty == .aterm <span class="tok-kw">or</span> token.ty == .sterm;</span>
<span class="line" id="L376">}</span>
<span class="line" id="L377"></span>
<span class="line" id="L378"><span class="tok-kw">fn</span> <span class="tok-fn">isSContinue</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L379"> <span class="tok-kw">return</span> token.ty == .scontinue;</span>
<span class="line" id="L380">}</span>
<span class="line" id="L381"></span>
<span class="line" id="L382"><span class="tok-kw">fn</span> <span class="tok-fn">isUnallowedBeforeLower</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L383"> <span class="tok-kw">return</span> token.ty == .oletter <span class="tok-kw">or</span> isUpperLower(token) <span class="tok-kw">or</span> isSATerm(token) <span class="tok-kw">or</span> isParaSep(token);</span>
<span class="line" id="L384">}</span>
<span class="line" id="L385"></span>
<span class="line" id="L386"><span class="tok-kw">fn</span> <span class="tok-fn">isAllowedBeforeLower</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L387"> <span class="tok-kw">return</span> !isUnallowedBeforeLower(token);</span>
<span class="line" id="L388">}</span>
<span class="line" id="L389"></span>
<span class="line" id="L390"><span class="tok-comment">// Comptime</span>
</span>
<span class="line" id="L391"><span class="tok-kw">fn</span> <span class="tok-fn">getTokens</span>(<span class="tok-kw">comptime</span> str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>, <span class="tok-kw">comptime</span> n: <span class="tok-type">usize</span>) [n]Token {</span>
<span class="line" id="L392"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L393"> <span class="tok-kw">var</span> cp_iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L394"> <span class="tok-kw">var</span> tokens: [n]Token = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L395"></span>
<span class="line" id="L396"> <span class="tok-kw">while</span> (cp_iter.next()) |cp| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L397"> tokens[i] = .{</span>
<span class="line" id="L398"> .ty = Type.get(cp),</span>
<span class="line" id="L399"> .code_point = cp,</span>
<span class="line" id="L400"> .offset = i,</span>
<span class="line" id="L401"> };</span>
<span class="line" id="L402"> }</span>
<span class="line" id="L403"></span>
<span class="line" id="L404"> <span class="tok-kw">return</span> tokens;</span>
<span class="line" id="L405">}</span>
<span class="line" id="L406"></span>
<span class="line" id="L407"><span class="tok-comment">/// `ComptimeSentenceIterator` is like `SentenceIterator` but requires a string literal to do its work at compile time.</span></span>
<span class="line" id="L408"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">ComptimeSentenceIterator</span>(<span class="tok-kw">comptime</span> str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">type</span> {</span>
<span class="line" id="L409"> <span class="tok-kw">const</span> cp_count: <span class="tok-type">usize</span> = unicode.utf8CountCodepoints(str) <span class="tok-kw">catch</span> <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;Invalid UTF-8.&quot;</span>);</span>
<span class="line" id="L410"> <span class="tok-kw">if</span> (cp_count == <span class="tok-number">0</span>) <span class="tok-builtin">@compileError</span>(<span class="tok-str">&quot;No code points?&quot;</span>);</span>
<span class="line" id="L411"> <span class="tok-kw">const</span> tokens = getTokens(str, cp_count);</span>
<span class="line" id="L412"></span>
<span class="line" id="L413"> <span class="tok-kw">return</span> <span class="tok-kw">struct</span> {</span>
<span class="line" id="L414"> bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span> = str,</span>
<span class="line" id="L415"> i: ?<span class="tok-type">usize</span> = <span class="tok-null">null</span>,</span>
<span class="line" id="L416"> start: ?Token = tokens[<span class="tok-number">0</span>],</span>
<span class="line" id="L417"> tokens: [cp_count]Token = tokens,</span>
<span class="line" id="L418"></span>
<span class="line" id="L419"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L420"></span>
<span class="line" id="L421"> <span class="tok-comment">// Main API.</span>
</span>
<span class="line" id="L422"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">next</span>(self: *Self) ?Sentence {</span>
<span class="line" id="L423"> no_break: <span class="tok-kw">while</span> (self.advance()) |current_token| {</span>
<span class="line" id="L424"> <span class="tok-kw">if</span> (isParaSep(current_token)) {</span>
<span class="line" id="L425"> <span class="tok-kw">var</span> end = current_token;</span>
<span class="line" id="L426"></span>
<span class="line" id="L427"> <span class="tok-kw">if</span> (current_token.is(.cr)) {</span>
<span class="line" id="L428"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L429"> <span class="tok-kw">if</span> (p.is(.lf)) {</span>
<span class="line" id="L430"> _ = self.advance();</span>
<span class="line" id="L431"> end = self.current();</span>
<span class="line" id="L432"> }</span>
<span class="line" id="L433"> }</span>
<span class="line" id="L434"> }</span>
<span class="line" id="L435"></span>
<span class="line" id="L436"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L437"> self.start = self.peek();</span>
<span class="line" id="L438"></span>
<span class="line" id="L439"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L440"> }</span>
<span class="line" id="L441"></span>
<span class="line" id="L442"> <span class="tok-kw">if</span> (current_token.is(.aterm)) {</span>
<span class="line" id="L443"> <span class="tok-kw">var</span> end = self.current();</span>
<span class="line" id="L444"></span>
<span class="line" id="L445"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L446"> <span class="tok-kw">if</span> (isUpper(p)) {</span>
<span class="line" id="L447"> <span class="tok-comment">// self.i may not be the same as current token's offset due to ignorable skipping.</span>
</span>
<span class="line" id="L448"> <span class="tok-kw">const</span> original_i = self.i;</span>
<span class="line" id="L449"> self.i = current_token.offset;</span>
<span class="line" id="L450"> <span class="tok-kw">defer</span> self.i = original_i;</span>
<span class="line" id="L451"></span>
<span class="line" id="L452"> <span class="tok-kw">if</span> (self.prevAfterSkip(isIgnorable)) |v| {</span>
<span class="line" id="L453"> <span class="tok-kw">if</span> (isUpperLower(v)) <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L454"> }</span>
<span class="line" id="L455"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isParaSep(p) <span class="tok-kw">or</span> isLower(p) <span class="tok-kw">or</span> isNumeric(p) <span class="tok-kw">or</span> isSContinue(p)) {</span>
<span class="line" id="L456"> <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L457"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isSpace(p)) {</span>
<span class="line" id="L458"> <span class="tok-comment">// ATerm Sp*</span>
</span>
<span class="line" id="L459"> self.run(isSpace);</span>
<span class="line" id="L460"> end = self.current();</span>
<span class="line" id="L461"> <span class="tok-comment">// Possible lower case after.</span>
</span>
<span class="line" id="L462"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L463"> <span class="tok-kw">if</span> (isLower(pp)) <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L464"> }</span>
<span class="line" id="L465"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isClose(p)) {</span>
<span class="line" id="L466"> <span class="tok-comment">// ATerm Close*</span>
</span>
<span class="line" id="L467"> self.run(isClose);</span>
<span class="line" id="L468"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L469"> <span class="tok-comment">// Possible ParaSep after.</span>
</span>
<span class="line" id="L470"> <span class="tok-kw">if</span> (isParaSep(pp)) {</span>
<span class="line" id="L471"> _ = self.advance();</span>
<span class="line" id="L472"> end = self.current();</span>
<span class="line" id="L473"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L474"> self.start = self.peek();</span>
<span class="line" id="L475"></span>
<span class="line" id="L476"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L477"> }</span>
<span class="line" id="L478"> <span class="tok-comment">// Possible spaces after.</span>
</span>
<span class="line" id="L479"> <span class="tok-kw">if</span> (isSpace(pp)) {</span>
<span class="line" id="L480"> <span class="tok-comment">// ATerm Close* Sp*</span>
</span>
<span class="line" id="L481"> self.run(isSpace);</span>
<span class="line" id="L482"></span>
<span class="line" id="L483"> <span class="tok-kw">if</span> (self.peek()) |ppp| {</span>
<span class="line" id="L484"> <span class="tok-comment">// Possible lower after.</span>
</span>
<span class="line" id="L485"> <span class="tok-kw">if</span> (isLower(ppp)) <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L486"> <span class="tok-comment">// Possible lower after some allowed code points.</span>
</span>
<span class="line" id="L487"> <span class="tok-kw">if</span> (isAllowedBeforeLower(ppp)) {</span>
<span class="line" id="L488"> <span class="tok-kw">if</span> (self.peekAfterSkip(isAllowedBeforeLower)) |pppp| {</span>
<span class="line" id="L489"> <span class="tok-comment">// ATerm Close* Sp* !(Unallowed) Lower</span>
</span>
<span class="line" id="L490"> <span class="tok-kw">if</span> (isLower(pppp)) <span class="tok-kw">continue</span> :no_break;</span>
<span class="line" id="L491"> }</span>
<span class="line" id="L492"> }</span>
<span class="line" id="L493"> }</span>
<span class="line" id="L494"> }</span>
<span class="line" id="L495"> }</span>
<span class="line" id="L496"></span>
<span class="line" id="L497"> end = self.current();</span>
<span class="line" id="L498"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isSATerm(p)) {</span>
<span class="line" id="L499"> self.run(isSATerm);</span>
<span class="line" id="L500"> end = self.current();</span>
<span class="line" id="L501"> }</span>
<span class="line" id="L502"> }</span>
<span class="line" id="L503"></span>
<span class="line" id="L504"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L505"> self.start = self.peek();</span>
<span class="line" id="L506"></span>
<span class="line" id="L507"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L508"> }</span>
<span class="line" id="L509"></span>
<span class="line" id="L510"> <span class="tok-kw">if</span> (current_token.is(.sterm)) {</span>
<span class="line" id="L511"> <span class="tok-kw">var</span> end = self.current();</span>
<span class="line" id="L512"></span>
<span class="line" id="L513"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L514"> <span class="tok-kw">if</span> (isParaSep(p) <span class="tok-kw">or</span> isSATerm(p) <span class="tok-kw">or</span> isSContinue(p)) {</span>
<span class="line" id="L515"> _ = self.advance();</span>
<span class="line" id="L516"> end = self.current();</span>
<span class="line" id="L517"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isSpace(p)) {</span>
<span class="line" id="L518"> self.run(isSpace);</span>
<span class="line" id="L519"> end = self.current();</span>
<span class="line" id="L520"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isClose(p)) {</span>
<span class="line" id="L521"> <span class="tok-comment">// STerm Close*</span>
</span>
<span class="line" id="L522"> self.run(isClose);</span>
<span class="line" id="L523"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L524"> <span class="tok-kw">if</span> (isSpace(pp)) {</span>
<span class="line" id="L525"> <span class="tok-comment">// STerm Close* Sp*</span>
</span>
<span class="line" id="L526"> self.run(isSpace);</span>
<span class="line" id="L527"> }</span>
<span class="line" id="L528"> }</span>
<span class="line" id="L529"></span>
<span class="line" id="L530"> end = self.current();</span>
<span class="line" id="L531"> }</span>
<span class="line" id="L532"> }</span>
<span class="line" id="L533"></span>
<span class="line" id="L534"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L535"> self.start = self.peek();</span>
<span class="line" id="L536"></span>
<span class="line" id="L537"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L538"> }</span>
<span class="line" id="L539"> }</span>
<span class="line" id="L540"></span>
<span class="line" id="L541"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (self.start) |start| self.emit(start, self.last()) <span class="tok-kw">else</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L542"> }</span>
<span class="line" id="L543"></span>
<span class="line" id="L544"> <span class="tok-comment">// Token array movement.</span>
</span>
<span class="line" id="L545"> <span class="tok-kw">fn</span> <span class="tok-fn">forward</span>(self: *Self) <span class="tok-type">bool</span> {</span>
<span class="line" id="L546"> <span class="tok-kw">if</span> (self.i) |*index| {</span>
<span class="line" id="L547"> index.* += <span class="tok-number">1</span>;</span>
<span class="line" id="L548"> <span class="tok-kw">if</span> (index.* &gt;= self.tokens.len) <span class="tok-kw">return</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L549"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L550"> self.i = <span class="tok-number">0</span>;</span>
<span class="line" id="L551"> }</span>
<span class="line" id="L552"></span>
<span class="line" id="L553"> <span class="tok-kw">return</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L554"> }</span>
<span class="line" id="L555"></span>
<span class="line" id="L556"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">count</span>(self: *Self) <span class="tok-type">usize</span> {</span>
<span class="line" id="L557"> <span class="tok-kw">const</span> original_i = self.i;</span>
<span class="line" id="L558"> <span class="tok-kw">const</span> original_start = self.start;</span>
<span class="line" id="L559"> <span class="tok-kw">defer</span> {</span>
<span class="line" id="L560"> self.i = original_i;</span>
<span class="line" id="L561"> self.start = original_start;</span>
<span class="line" id="L562"> }</span>
<span class="line" id="L563"></span>
<span class="line" id="L564"> self.rewind();</span>
<span class="line" id="L565"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L566"> <span class="tok-kw">while</span> (self.next()) |_| : (i += <span class="tok-number">1</span>) {}</span>
<span class="line" id="L567"></span>
<span class="line" id="L568"> <span class="tok-kw">return</span> i;</span>
<span class="line" id="L569"> }</span>
<span class="line" id="L570"></span>
<span class="line" id="L571"> <span class="tok-comment">// Token array movement.</span>
</span>
<span class="line" id="L572"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">rewind</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L573"> self.i = <span class="tok-null">null</span>;</span>
<span class="line" id="L574"> self.start = self.tokens[<span class="tok-number">0</span>];</span>
<span class="line" id="L575"> }</span>
<span class="line" id="L576"></span>
<span class="line" id="L577"> <span class="tok-kw">fn</span> <span class="tok-fn">getRelative</span>(self: Self, n: <span class="tok-type">isize</span>) ?Token {</span>
<span class="line" id="L578"> <span class="tok-kw">var</span> index: <span class="tok-type">usize</span> = self.i <span class="tok-kw">orelse</span> <span class="tok-number">0</span>;</span>
<span class="line" id="L579"></span>
<span class="line" id="L580"> <span class="tok-kw">if</span> (n &lt; <span class="tok-number">0</span>) {</span>
<span class="line" id="L581"> <span class="tok-kw">if</span> (index == <span class="tok-number">0</span> <span class="tok-kw">or</span> -%n &gt; index) <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L582"> index -= <span class="tok-builtin">@intCast</span>(-%n);</span>
<span class="line" id="L583"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L584"> <span class="tok-kw">const</span> un: <span class="tok-type">usize</span> = <span class="tok-builtin">@intCast</span>(n);</span>
<span class="line" id="L585"> <span class="tok-kw">if</span> (index + un &gt;= self.tokens.len) <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L586"> index += un;</span>
<span class="line" id="L587"> }</span>
<span class="line" id="L588"></span>
<span class="line" id="L589"> <span class="tok-kw">return</span> self.tokens[index];</span>
<span class="line" id="L590"> }</span>
<span class="line" id="L591"></span>
<span class="line" id="L592"> <span class="tok-kw">fn</span> <span class="tok-fn">prevAfterSkip</span>(self: *Self, predicate: TokenPredicate) ?Token {</span>
<span class="line" id="L593"> <span class="tok-kw">if</span> (self.i == <span class="tok-null">null</span> <span class="tok-kw">or</span> self.i.? == <span class="tok-number">0</span>) <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L594"></span>
<span class="line" id="L595"> <span class="tok-kw">var</span> i: <span class="tok-type">isize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L596"> <span class="tok-kw">while</span> (self.getRelative(-i)) |token| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L597"> <span class="tok-kw">if</span> (!predicate(token)) <span class="tok-kw">return</span> token;</span>
<span class="line" id="L598"> }</span>
<span class="line" id="L599"></span>
<span class="line" id="L600"> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L601"> }</span>
<span class="line" id="L602"></span>
<span class="line" id="L603"> <span class="tok-kw">fn</span> <span class="tok-fn">current</span>(self: Self) Token {</span>
<span class="line" id="L604"> <span class="tok-comment">// Assumes self.i is not null.</span>
</span>
<span class="line" id="L605"> <span class="tok-kw">return</span> self.tokens[self.i.?];</span>
<span class="line" id="L606"> }</span>
<span class="line" id="L607"></span>
<span class="line" id="L608"> <span class="tok-kw">fn</span> <span class="tok-fn">last</span>(self: Self) Token {</span>
<span class="line" id="L609"> <span class="tok-kw">return</span> self.tokens[self.tokens.len - <span class="tok-number">1</span>];</span>
<span class="line" id="L610"> }</span>
<span class="line" id="L611"></span>
<span class="line" id="L612"> <span class="tok-kw">fn</span> <span class="tok-fn">peek</span>(self: Self) ?Token {</span>
<span class="line" id="L613"> <span class="tok-kw">return</span> self.getRelative(<span class="tok-number">1</span>);</span>
<span class="line" id="L614"> }</span>
<span class="line" id="L615"></span>
<span class="line" id="L616"> <span class="tok-kw">fn</span> <span class="tok-fn">peekAfterSkip</span>(self: *Self, predicate: TokenPredicate) ?Token {</span>
<span class="line" id="L617"> <span class="tok-kw">var</span> i: <span class="tok-type">isize</span> = <span class="tok-number">1</span>;</span>
<span class="line" id="L618"> <span class="tok-kw">while</span> (self.getRelative(i)) |token| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L619"> <span class="tok-kw">if</span> (!predicate(token)) <span class="tok-kw">return</span> token;</span>
<span class="line" id="L620"> }</span>
<span class="line" id="L621"></span>
<span class="line" id="L622"> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L623"> }</span>
<span class="line" id="L624"></span>
<span class="line" id="L625"> <span class="tok-kw">fn</span> <span class="tok-fn">advance</span>(self: *Self) ?Token {</span>
<span class="line" id="L626"> <span class="tok-kw">const</span> token = <span class="tok-kw">if</span> (self.forward()) self.current() <span class="tok-kw">else</span> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L627"> <span class="tok-kw">if</span> (!isParaSep(token)) _ = self.skipIgnorables(token);</span>
<span class="line" id="L628"></span>
<span class="line" id="L629"> <span class="tok-kw">return</span> token;</span>
<span class="line" id="L630"> }</span>
<span class="line" id="L631"></span>
<span class="line" id="L632"> <span class="tok-kw">fn</span> <span class="tok-fn">run</span>(self: *Self, predicate: TokenPredicate) <span class="tok-type">void</span> {</span>
<span class="line" id="L633"> <span class="tok-kw">while</span> (self.peek()) |token| {</span>
<span class="line" id="L634"> <span class="tok-kw">if</span> (!predicate(token)) <span class="tok-kw">break</span>;</span>
<span class="line" id="L635"> _ = self.advance();</span>
<span class="line" id="L636"> }</span>
<span class="line" id="L637"> }</span>
<span class="line" id="L638"></span>
<span class="line" id="L639"> <span class="tok-kw">fn</span> <span class="tok-fn">skipIgnorables</span>(self: *Self, end: Token) Token {</span>
<span class="line" id="L640"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L641"> <span class="tok-kw">if</span> (isIgnorable(p)) {</span>
<span class="line" id="L642"> self.run(isIgnorable);</span>
<span class="line" id="L643"> <span class="tok-kw">return</span> self.current();</span>
<span class="line" id="L644"> }</span>
<span class="line" id="L645"> }</span>
<span class="line" id="L646"></span>
<span class="line" id="L647"> <span class="tok-kw">return</span> end;</span>
<span class="line" id="L648"> }</span>
<span class="line" id="L649"></span>
<span class="line" id="L650"> <span class="tok-comment">// Production.</span>
</span>
<span class="line" id="L651"> <span class="tok-kw">fn</span> <span class="tok-fn">emit</span>(self: Self, start_token: Token, end_token: Token) Sentence {</span>
<span class="line" id="L652"> <span class="tok-kw">const</span> start = start_token.code_point.offset;</span>
<span class="line" id="L653"> <span class="tok-kw">const</span> end = end_token.code_point.offset + end_token.code_point.len;</span>
<span class="line" id="L654"></span>
<span class="line" id="L655"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L656"> .bytes = self.bytes[start..end],</span>
<span class="line" id="L657"> .offset = start,</span>
<span class="line" id="L658"> };</span>
<span class="line" id="L659"> }</span>
<span class="line" id="L660"> };</span>
<span class="line" id="L661">}</span>
<span class="line" id="L662"></span>
<span class="line" id="L663"><span class="tok-kw">test</span> <span class="tok-str">&quot;Segmentation ComptimeSentenceIterator&quot;</span> {</span>
<span class="line" id="L664"> <span class="tok-builtin">@setEvalBranchQuota</span>(<span class="tok-number">2_000</span>);</span>
<span class="line" id="L665"></span>
<span class="line" id="L666"> <span class="tok-kw">const</span> input =</span>
<span class="line" id="L667"> <span class="tok-str">\\(&quot;Go.&quot;) (&quot;He said.&quot;)</span></span>
<span class="line" id="L668"> ;</span>
<span class="line" id="L669"> <span class="tok-kw">comptime</span> <span class="tok-kw">var</span> ct_iter = ComptimeSentenceIterator(input){};</span>
<span class="line" id="L670"> <span class="tok-kw">const</span> n = <span class="tok-kw">comptime</span> ct_iter.count();</span>
<span class="line" id="L671"> <span class="tok-kw">comptime</span> <span class="tok-kw">var</span> sentences: [n]Sentence = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L672"> <span class="tok-kw">comptime</span> {</span>
<span class="line" id="L673"> <span class="tok-kw">var</span> i: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L674"> <span class="tok-kw">while</span> (ct_iter.next()) |sentence| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L675"> sentences[i] = sentence;</span>
<span class="line" id="L676"> }</span>
<span class="line" id="L677"> }</span>
<span class="line" id="L678"></span>
<span class="line" id="L679"> <span class="tok-kw">const</span> s1 =</span>
<span class="line" id="L680"> <span class="tok-str">\\(&quot;Go.&quot;) </span></span>
<span class="line" id="L681"> ;</span>
<span class="line" id="L682"> <span class="tok-kw">const</span> s2 =</span>
<span class="line" id="L683"> <span class="tok-str">\\(&quot;He said.&quot;)</span></span>
<span class="line" id="L684"> ;</span>
<span class="line" id="L685"> <span class="tok-kw">const</span> want = &amp;[_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ s1, s2 };</span>
<span class="line" id="L686"></span>
<span class="line" id="L687"> <span class="tok-kw">for</span> (sentences, <span class="tok-number">0</span>..) |sentence, i| {</span>
<span class="line" id="L688"> <span class="tok-kw">try</span> std.testing.expect(sentence.eql(want[i]));</span>
<span class="line" id="L689"> }</span>
<span class="line" id="L690">}</span>
<span class="line" id="L691"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,572 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>segmenter/Word.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `Word` represents a single word within a UTF-8 encoded string by its bytes and offset.</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> unicode = std.unicode;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-kw">const</span> wbp = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/word_break_property.zig&quot;</span>);</span>
<span class="line" id="L7"><span class="tok-kw">const</span> CodePoint = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;CodePoint.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">const</span> CodePointIterator = CodePoint.CodePointIterator;</span>
<span class="line" id="L9"><span class="tok-kw">const</span> emoji = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;../autogen/emoji_data.zig&quot;</span>);</span>
<span class="line" id="L10"></span>
<span class="line" id="L11"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Word = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L12"></span>
<span class="line" id="L13">bytes: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>,</span>
<span class="line" id="L14">offset: <span class="tok-type">usize</span>,</span>
<span class="line" id="L15"></span>
<span class="line" id="L16"><span class="tok-comment">/// `eal` compares `str` with the bytes of this word for equality.</span></span>
<span class="line" id="L17"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">eql</span>(self: Word, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L18"> <span class="tok-kw">return</span> std.mem.eql(<span class="tok-type">u8</span>, self.bytes, str);</span>
<span class="line" id="L19">}</span>
<span class="line" id="L20"></span>
<span class="line" id="L21"><span class="tok-kw">const</span> Type = <span class="tok-kw">enum</span> {</span>
<span class="line" id="L22"> aletter,</span>
<span class="line" id="L23"> cr,</span>
<span class="line" id="L24"> dquote,</span>
<span class="line" id="L25"> extend,</span>
<span class="line" id="L26"> extendnumlet,</span>
<span class="line" id="L27"> format,</span>
<span class="line" id="L28"> hletter,</span>
<span class="line" id="L29"> katakana,</span>
<span class="line" id="L30"> lf,</span>
<span class="line" id="L31"> midletter,</span>
<span class="line" id="L32"> midnum,</span>
<span class="line" id="L33"> midnumlet,</span>
<span class="line" id="L34"> newline,</span>
<span class="line" id="L35"> numeric,</span>
<span class="line" id="L36"> regional,</span>
<span class="line" id="L37"> squote,</span>
<span class="line" id="L38"> wsegspace,</span>
<span class="line" id="L39"> xpic,</span>
<span class="line" id="L40"> zwj,</span>
<span class="line" id="L41"> any,</span>
<span class="line" id="L42"></span>
<span class="line" id="L43"> <span class="tok-kw">fn</span> <span class="tok-fn">get</span>(cp: CodePoint) Type {</span>
<span class="line" id="L44"> <span class="tok-kw">var</span> ty: Type = .any;</span>
<span class="line" id="L45"> <span class="tok-kw">if</span> (<span class="tok-number">0x000D</span> == cp.code) ty = .cr;</span>
<span class="line" id="L46"> <span class="tok-kw">if</span> (<span class="tok-number">0x000A</span> == cp.code) ty = .lf;</span>
<span class="line" id="L47"> <span class="tok-kw">if</span> (<span class="tok-number">0x200D</span> == cp.code) ty = .zwj;</span>
<span class="line" id="L48"> <span class="tok-kw">if</span> (<span class="tok-number">0x0022</span> == cp.code) ty = .dquote;</span>
<span class="line" id="L49"> <span class="tok-kw">if</span> (<span class="tok-number">0x0027</span> == cp.code) ty = .squote;</span>
<span class="line" id="L50"> <span class="tok-kw">if</span> (wbp.isAletter(cp.code)) ty = .aletter;</span>
<span class="line" id="L51"> <span class="tok-kw">if</span> (wbp.isExtend(cp.code)) ty = .extend;</span>
<span class="line" id="L52"> <span class="tok-kw">if</span> (wbp.isExtendnumlet(cp.code)) ty = .extendnumlet;</span>
<span class="line" id="L53"> <span class="tok-kw">if</span> (wbp.isFormat(cp.code)) ty = .format;</span>
<span class="line" id="L54"> <span class="tok-kw">if</span> (wbp.isHebrewLetter(cp.code)) ty = .hletter;</span>
<span class="line" id="L55"> <span class="tok-kw">if</span> (wbp.isKatakana(cp.code)) ty = .katakana;</span>
<span class="line" id="L56"> <span class="tok-kw">if</span> (wbp.isMidletter(cp.code)) ty = .midletter;</span>
<span class="line" id="L57"> <span class="tok-kw">if</span> (wbp.isMidnum(cp.code)) ty = .midnum;</span>
<span class="line" id="L58"> <span class="tok-kw">if</span> (wbp.isMidnumlet(cp.code)) ty = .midnumlet;</span>
<span class="line" id="L59"> <span class="tok-kw">if</span> (wbp.isNewline(cp.code)) ty = .newline;</span>
<span class="line" id="L60"> <span class="tok-kw">if</span> (wbp.isNumeric(cp.code)) ty = .numeric;</span>
<span class="line" id="L61"> <span class="tok-kw">if</span> (wbp.isRegionalIndicator(cp.code)) ty = .regional;</span>
<span class="line" id="L62"> <span class="tok-kw">if</span> (wbp.isWsegspace(cp.code)) ty = .wsegspace;</span>
<span class="line" id="L63"> <span class="tok-kw">if</span> (emoji.isExtendedPictographic(cp.code)) ty = .xpic;</span>
<span class="line" id="L64"></span>
<span class="line" id="L65"> <span class="tok-kw">return</span> ty;</span>
<span class="line" id="L66"> }</span>
<span class="line" id="L67">};</span>
<span class="line" id="L68"></span>
<span class="line" id="L69"><span class="tok-kw">const</span> Token = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L70"> ty: Type,</span>
<span class="line" id="L71"> code_point: CodePoint,</span>
<span class="line" id="L72"></span>
<span class="line" id="L73"> <span class="tok-kw">fn</span> <span class="tok-fn">is</span>(self: Token, ty: Type) <span class="tok-type">bool</span> {</span>
<span class="line" id="L74"> <span class="tok-kw">return</span> self.ty == ty;</span>
<span class="line" id="L75"> }</span>
<span class="line" id="L76">};</span>
<span class="line" id="L77"></span>
<span class="line" id="L78"><span class="tok-comment">/// `WordIterator` iterates a Unicode string one word at-a-time. Note that whitespace and punctuation appear as separate</span></span>
<span class="line" id="L79"><span class="tok-comment">/// elements in the iteration.</span></span>
<span class="line" id="L80"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> WordIterator = <span class="tok-kw">struct</span> {</span>
<span class="line" id="L81"> cp_iter: CodePointIterator,</span>
<span class="line" id="L82"> current: ?Token = <span class="tok-null">null</span>,</span>
<span class="line" id="L83"> start: ?Token = <span class="tok-null">null</span>,</span>
<span class="line" id="L84"></span>
<span class="line" id="L85"> <span class="tok-kw">const</span> Self = <span class="tok-builtin">@This</span>();</span>
<span class="line" id="L86"></span>
<span class="line" id="L87"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">init</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) !Self {</span>
<span class="line" id="L88"> <span class="tok-kw">if</span> (!unicode.utf8ValidateSlice(str)) <span class="tok-kw">return</span> <span class="tok-kw">error</span>.InvalidUtf8;</span>
<span class="line" id="L89"> <span class="tok-kw">return</span> Self{ .cp_iter = CodePointIterator{ .bytes = str } };</span>
<span class="line" id="L90"> }</span>
<span class="line" id="L91"></span>
<span class="line" id="L92"> <span class="tok-comment">// Main API.</span>
</span>
<span class="line" id="L93"> <span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">next</span>(self: *Self) ?Word {</span>
<span class="line" id="L94"> <span class="tok-kw">if</span> (self.advance()) |latest_non_ignorable| {</span>
<span class="line" id="L95"> <span class="tok-kw">var</span> end = self.current.?;</span>
<span class="line" id="L96"> <span class="tok-kw">var</span> done = <span class="tok-null">false</span>;</span>
<span class="line" id="L97"></span>
<span class="line" id="L98"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> isBreaker(latest_non_ignorable)) {</span>
<span class="line" id="L99"> <span class="tok-kw">if</span> (latest_non_ignorable.is(.cr)) {</span>
<span class="line" id="L100"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L101"> <span class="tok-comment">// WB</span>
</span>
<span class="line" id="L102"> <span class="tok-kw">if</span> (p.is(.lf)) {</span>
<span class="line" id="L103"> _ = self.advance();</span>
<span class="line" id="L104"> end = self.current.?;</span>
<span class="line" id="L105"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L106"> }</span>
<span class="line" id="L107"> }</span>
<span class="line" id="L108"> }</span>
<span class="line" id="L109"> }</span>
<span class="line" id="L110"></span>
<span class="line" id="L111"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> end.is(.zwj)) {</span>
<span class="line" id="L112"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L113"> <span class="tok-comment">// WB3c</span>
</span>
<span class="line" id="L114"> <span class="tok-kw">if</span> (p.is(.xpic)) {</span>
<span class="line" id="L115"> _ = self.advance();</span>
<span class="line" id="L116"> end = self.current.?;</span>
<span class="line" id="L117"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L118"> }</span>
<span class="line" id="L119"> }</span>
<span class="line" id="L120"> }</span>
<span class="line" id="L121"></span>
<span class="line" id="L122"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> latest_non_ignorable.is(.wsegspace)) {</span>
<span class="line" id="L123"> <span class="tok-kw">while</span> (self.peek()) |p| {</span>
<span class="line" id="L124"> <span class="tok-comment">// WB3d</span>
</span>
<span class="line" id="L125"> <span class="tok-kw">if</span> (p.is(.wsegspace) <span class="tok-kw">and</span> !isIgnorable(end)) {</span>
<span class="line" id="L126"> _ = self.advance();</span>
<span class="line" id="L127"> end = self.current.?;</span>
<span class="line" id="L128"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L129"> } <span class="tok-kw">else</span> <span class="tok-kw">break</span>;</span>
<span class="line" id="L130"> }</span>
<span class="line" id="L131"> }</span>
<span class="line" id="L132"></span>
<span class="line" id="L133"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> (isAHLetter(latest_non_ignorable) <span class="tok-kw">or</span> latest_non_ignorable.is(.numeric))) {</span>
<span class="line" id="L134"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L135"> <span class="tok-comment">// WB5, WB8, WB9, WB10</span>
</span>
<span class="line" id="L136"> <span class="tok-kw">if</span> (isAHLetter(p) <span class="tok-kw">or</span> p.is(.numeric)) {</span>
<span class="line" id="L137"> self.run(isAlphaNum);</span>
<span class="line" id="L138"> end = self.current.?;</span>
<span class="line" id="L139"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L140"> }</span>
<span class="line" id="L141"> }</span>
<span class="line" id="L142"> }</span>
<span class="line" id="L143"></span>
<span class="line" id="L144"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> isAHLetter(latest_non_ignorable)) {</span>
<span class="line" id="L145"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L146"> <span class="tok-comment">// WB6, WB7</span>
</span>
<span class="line" id="L147"> <span class="tok-kw">if</span> (p.is(.midletter) <span class="tok-kw">or</span> isMidNumLetQ(p)) {</span>
<span class="line" id="L148"> <span class="tok-comment">// Save state</span>
</span>
<span class="line" id="L149"> <span class="tok-kw">const</span> saved_i = self.cp_iter.i;</span>
<span class="line" id="L150"> <span class="tok-kw">const</span> saved_current = self.current;</span>
<span class="line" id="L151"> <span class="tok-kw">const</span> saved_start = self.start;</span>
<span class="line" id="L152"></span>
<span class="line" id="L153"> _ = self.advance(); <span class="tok-comment">// (MidLetter|MidNumLetQ)</span>
</span>
<span class="line" id="L154"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L155"> <span class="tok-kw">if</span> (isAHLetter(pp)) {</span>
<span class="line" id="L156"> _ = self.advance(); <span class="tok-comment">// AHLetter</span>
</span>
<span class="line" id="L157"> end = self.current.?;</span>
<span class="line" id="L158"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L159"> }</span>
<span class="line" id="L160"> }</span>
<span class="line" id="L161"></span>
<span class="line" id="L162"> <span class="tok-kw">if</span> (!done) {</span>
<span class="line" id="L163"> <span class="tok-comment">// Restore state</span>
</span>
<span class="line" id="L164"> self.cp_iter.i = saved_i;</span>
<span class="line" id="L165"> self.current = saved_current;</span>
<span class="line" id="L166"> self.start = saved_start;</span>
<span class="line" id="L167"> }</span>
<span class="line" id="L168"> }</span>
<span class="line" id="L169"> }</span>
<span class="line" id="L170"> }</span>
<span class="line" id="L171"></span>
<span class="line" id="L172"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> latest_non_ignorable.is(.hletter)) {</span>
<span class="line" id="L173"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L174"> <span class="tok-comment">// WB7a</span>
</span>
<span class="line" id="L175"> <span class="tok-kw">if</span> (p.is(.squote)) {</span>
<span class="line" id="L176"> _ = self.advance();</span>
<span class="line" id="L177"> end = self.current.?;</span>
<span class="line" id="L178"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L179"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (p.is(.dquote)) {</span>
<span class="line" id="L180"> <span class="tok-comment">// WB7b, WB7c</span>
</span>
<span class="line" id="L181"> <span class="tok-comment">// Save state</span>
</span>
<span class="line" id="L182"> <span class="tok-kw">const</span> saved_i = self.cp_iter.i;</span>
<span class="line" id="L183"> <span class="tok-kw">const</span> saved_current = self.current;</span>
<span class="line" id="L184"> <span class="tok-kw">const</span> saved_start = self.start;</span>
<span class="line" id="L185"></span>
<span class="line" id="L186"> _ = self.advance(); <span class="tok-comment">// Double_Quote</span>
</span>
<span class="line" id="L187"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L188"> <span class="tok-kw">if</span> (pp.is(.hletter)) {</span>
<span class="line" id="L189"> _ = self.advance(); <span class="tok-comment">// Hebrew_Letter</span>
</span>
<span class="line" id="L190"> end = self.current.?;</span>
<span class="line" id="L191"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L192"> }</span>
<span class="line" id="L193"> }</span>
<span class="line" id="L194"></span>
<span class="line" id="L195"> <span class="tok-kw">if</span> (!done) {</span>
<span class="line" id="L196"> <span class="tok-comment">// Restore state</span>
</span>
<span class="line" id="L197"> self.cp_iter.i = saved_i;</span>
<span class="line" id="L198"> self.current = saved_current;</span>
<span class="line" id="L199"> self.start = saved_start;</span>
<span class="line" id="L200"> }</span>
<span class="line" id="L201"> }</span>
<span class="line" id="L202"> }</span>
<span class="line" id="L203"> }</span>
<span class="line" id="L204"></span>
<span class="line" id="L205"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> latest_non_ignorable.is(.numeric)) {</span>
<span class="line" id="L206"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L207"> <span class="tok-kw">if</span> (p.is(.midnum) <span class="tok-kw">or</span> isMidNumLetQ(p)) {</span>
<span class="line" id="L208"> <span class="tok-comment">// WB11, WB12</span>
</span>
<span class="line" id="L209"> <span class="tok-comment">// Save state</span>
</span>
<span class="line" id="L210"> <span class="tok-kw">const</span> saved_i = self.cp_iter.i;</span>
<span class="line" id="L211"> <span class="tok-kw">const</span> saved_current = self.current;</span>
<span class="line" id="L212"> <span class="tok-kw">const</span> saved_start = self.start;</span>
<span class="line" id="L213"></span>
<span class="line" id="L214"> _ = self.advance(); <span class="tok-comment">// (MidNum|MidNumLetQ)</span>
</span>
<span class="line" id="L215"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L216"> <span class="tok-kw">if</span> (pp.is(.numeric)) {</span>
<span class="line" id="L217"> _ = self.advance(); <span class="tok-comment">// Numeric</span>
</span>
<span class="line" id="L218"> end = self.current.?;</span>
<span class="line" id="L219"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L220"> }</span>
<span class="line" id="L221"> }</span>
<span class="line" id="L222"></span>
<span class="line" id="L223"> <span class="tok-kw">if</span> (!done) {</span>
<span class="line" id="L224"> <span class="tok-comment">// Restore state</span>
</span>
<span class="line" id="L225"> self.cp_iter.i = saved_i;</span>
<span class="line" id="L226"> self.current = saved_current;</span>
<span class="line" id="L227"> self.start = saved_start;</span>
<span class="line" id="L228"> }</span>
<span class="line" id="L229"> }</span>
<span class="line" id="L230"> }</span>
<span class="line" id="L231"> }</span>
<span class="line" id="L232"></span>
<span class="line" id="L233"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> (isAHLetter(latest_non_ignorable) <span class="tok-kw">or</span> latest_non_ignorable.is(.numeric) <span class="tok-kw">or</span> latest_non_ignorable.is(.katakana) <span class="tok-kw">or</span></span>
<span class="line" id="L234"> latest_non_ignorable.is(.extendnumlet)))</span>
<span class="line" id="L235"> {</span>
<span class="line" id="L236"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L237"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L238"> <span class="tok-comment">// WB13a</span>
</span>
<span class="line" id="L239"> <span class="tok-kw">if</span> (p.is(.extendnumlet)) {</span>
<span class="line" id="L240"> _ = self.advance(); <span class="tok-comment">// ExtendNumLet</span>
</span>
<span class="line" id="L241"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L242"> <span class="tok-kw">if</span> (isAHLetter(pp) <span class="tok-kw">or</span> isNumeric(pp) <span class="tok-kw">or</span> pp.is(.katakana)) {</span>
<span class="line" id="L243"> <span class="tok-comment">// WB13b</span>
</span>
<span class="line" id="L244"> _ = self.advance(); <span class="tok-comment">// (AHLetter|Numeric|Katakana)</span>
</span>
<span class="line" id="L245"> }</span>
<span class="line" id="L246"> }</span>
<span class="line" id="L247"> end = self.current.?;</span>
<span class="line" id="L248"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L249"> } <span class="tok-kw">else</span> <span class="tok-kw">break</span>;</span>
<span class="line" id="L250"> } <span class="tok-kw">else</span> <span class="tok-kw">break</span>;</span>
<span class="line" id="L251"> }</span>
<span class="line" id="L252"> }</span>
<span class="line" id="L253"></span>
<span class="line" id="L254"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> latest_non_ignorable.is(.extendnumlet)) {</span>
<span class="line" id="L255"> <span class="tok-kw">while</span> (<span class="tok-null">true</span>) {</span>
<span class="line" id="L256"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L257"> <span class="tok-comment">// WB13b</span>
</span>
<span class="line" id="L258"> <span class="tok-kw">if</span> (isAHLetter(p) <span class="tok-kw">or</span> p.is(.numeric) <span class="tok-kw">or</span> p.is(.katakana)) {</span>
<span class="line" id="L259"> _ = self.advance(); <span class="tok-comment">// (AHLetter|Numeric|Katakana)</span>
</span>
<span class="line" id="L260"> end = self.current.?;</span>
<span class="line" id="L261"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L262"></span>
<span class="line" id="L263"> <span class="tok-kw">if</span> (self.peek()) |pp| {</span>
<span class="line" id="L264"> <span class="tok-comment">// Chain.</span>
</span>
<span class="line" id="L265"> <span class="tok-kw">if</span> (pp.is(.extendnumlet)) {</span>
<span class="line" id="L266"> _ = self.advance(); <span class="tok-comment">// ExtendNumLet</span>
</span>
<span class="line" id="L267"> <span class="tok-kw">continue</span>;</span>
<span class="line" id="L268"> }</span>
<span class="line" id="L269"> }</span>
<span class="line" id="L270"> } <span class="tok-kw">else</span> <span class="tok-kw">break</span>;</span>
<span class="line" id="L271"> } <span class="tok-kw">else</span> <span class="tok-kw">break</span>;</span>
<span class="line" id="L272"> }</span>
<span class="line" id="L273"> }</span>
<span class="line" id="L274"></span>
<span class="line" id="L275"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> latest_non_ignorable.is(.katakana)) {</span>
<span class="line" id="L276"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L277"> <span class="tok-comment">// WB13</span>
</span>
<span class="line" id="L278"> <span class="tok-kw">if</span> (p.is(.katakana)) {</span>
<span class="line" id="L279"> _ = self.advance();</span>
<span class="line" id="L280"> end = self.current.?;</span>
<span class="line" id="L281"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L282"> }</span>
<span class="line" id="L283"> }</span>
<span class="line" id="L284"> }</span>
<span class="line" id="L285"></span>
<span class="line" id="L286"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> latest_non_ignorable.is(.regional)) {</span>
<span class="line" id="L287"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L288"> <span class="tok-comment">// WB</span>
</span>
<span class="line" id="L289"> <span class="tok-kw">if</span> (p.is(.regional)) {</span>
<span class="line" id="L290"> _ = self.advance();</span>
<span class="line" id="L291"> end = self.current.?;</span>
<span class="line" id="L292"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L293"> }</span>
<span class="line" id="L294"> }</span>
<span class="line" id="L295"> }</span>
<span class="line" id="L296"></span>
<span class="line" id="L297"> <span class="tok-kw">if</span> (!done <span class="tok-kw">and</span> latest_non_ignorable.is(.xpic)) {</span>
<span class="line" id="L298"> <span class="tok-kw">if</span> (self.peek()) |p| {</span>
<span class="line" id="L299"> <span class="tok-comment">// WB</span>
</span>
<span class="line" id="L300"> <span class="tok-kw">if</span> (p.is(.xpic) <span class="tok-kw">and</span> end.is(.zwj)) {</span>
<span class="line" id="L301"> _ = self.advance();</span>
<span class="line" id="L302"> end = self.current.?;</span>
<span class="line" id="L303"> done = <span class="tok-null">true</span>;</span>
<span class="line" id="L304"> }</span>
<span class="line" id="L305"> }</span>
<span class="line" id="L306"> }</span>
<span class="line" id="L307"></span>
<span class="line" id="L308"> <span class="tok-kw">const</span> start = self.start.?;</span>
<span class="line" id="L309"> self.start = self.peek();</span>
<span class="line" id="L310"></span>
<span class="line" id="L311"> <span class="tok-comment">// WB</span>
</span>
<span class="line" id="L312"> <span class="tok-kw">return</span> self.emit(start, end);</span>
<span class="line" id="L313"> }</span>
<span class="line" id="L314"></span>
<span class="line" id="L315"> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L316"> }</span>
<span class="line" id="L317"></span>
<span class="line" id="L318"> <span class="tok-kw">fn</span> <span class="tok-fn">peek</span>(self: *Self) ?Token {</span>
<span class="line" id="L319"> <span class="tok-kw">const</span> saved_i = self.cp_iter.i;</span>
<span class="line" id="L320"> <span class="tok-kw">defer</span> self.cp_iter.i = saved_i;</span>
<span class="line" id="L321"></span>
<span class="line" id="L322"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (self.cp_iter.next()) |cp| Token{</span>
<span class="line" id="L323"> .ty = Type.get(cp),</span>
<span class="line" id="L324"> .code_point = cp,</span>
<span class="line" id="L325"> } <span class="tok-kw">else</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L326"> }</span>
<span class="line" id="L327"></span>
<span class="line" id="L328"> <span class="tok-kw">fn</span> <span class="tok-fn">advance</span>(self: *Self) ?Token {</span>
<span class="line" id="L329"> <span class="tok-kw">const</span> latest_non_ignorable = <span class="tok-kw">if</span> (self.cp_iter.next()) |cp| Token{</span>
<span class="line" id="L330"> .ty = Type.get(cp),</span>
<span class="line" id="L331"> .code_point = cp,</span>
<span class="line" id="L332"> } <span class="tok-kw">else</span> <span class="tok-kw">return</span> <span class="tok-null">null</span>;</span>
<span class="line" id="L333"></span>
<span class="line" id="L334"> self.current = latest_non_ignorable;</span>
<span class="line" id="L335"> <span class="tok-kw">if</span> (self.start == <span class="tok-null">null</span>) self.start = latest_non_ignorable; <span class="tok-comment">// Happens only at beginning.</span>
</span>
<span class="line" id="L336"></span>
<span class="line" id="L337"> <span class="tok-comment">// WB3a, WB3b</span>
</span>
<span class="line" id="L338"> <span class="tok-kw">if</span> (!isBreaker(latest_non_ignorable)) self.skipIgnorables();</span>
<span class="line" id="L339"></span>
<span class="line" id="L340"> <span class="tok-kw">return</span> latest_non_ignorable;</span>
<span class="line" id="L341"> }</span>
<span class="line" id="L342"></span>
<span class="line" id="L343"> <span class="tok-kw">fn</span> <span class="tok-fn">run</span>(self: *Self, predicate: TokenPredicate) <span class="tok-type">void</span> {</span>
<span class="line" id="L344"> <span class="tok-kw">while</span> (self.peek()) |token| {</span>
<span class="line" id="L345"> <span class="tok-kw">if</span> (!predicate(token)) <span class="tok-kw">break</span>;</span>
<span class="line" id="L346"> _ = self.advance();</span>
<span class="line" id="L347"> }</span>
<span class="line" id="L348"> }</span>
<span class="line" id="L349"></span>
<span class="line" id="L350"> <span class="tok-kw">fn</span> <span class="tok-fn">skipIgnorables</span>(self: *Self) <span class="tok-type">void</span> {</span>
<span class="line" id="L351"> <span class="tok-kw">while</span> (self.peek()) |peek_token| {</span>
<span class="line" id="L352"> <span class="tok-kw">if</span> (!isIgnorable(peek_token)) <span class="tok-kw">break</span>;</span>
<span class="line" id="L353"> _ = self.advance();</span>
<span class="line" id="L354"> }</span>
<span class="line" id="L355"> }</span>
<span class="line" id="L356"></span>
<span class="line" id="L357"> <span class="tok-comment">// Production.</span>
</span>
<span class="line" id="L358"> <span class="tok-kw">fn</span> <span class="tok-fn">emit</span>(self: Self, start_token: Token, end_token: Token) Word {</span>
<span class="line" id="L359"> <span class="tok-kw">const</span> start = start_token.code_point.offset;</span>
<span class="line" id="L360"> <span class="tok-kw">const</span> end = end_token.code_point.offset + end_token.code_point.len;</span>
<span class="line" id="L361"></span>
<span class="line" id="L362"> <span class="tok-kw">return</span> .{</span>
<span class="line" id="L363"> .bytes = self.cp_iter.bytes[start..end],</span>
<span class="line" id="L364"> .offset = start,</span>
<span class="line" id="L365"> };</span>
<span class="line" id="L366"> }</span>
<span class="line" id="L367">};</span>
<span class="line" id="L368"></span>
<span class="line" id="L369"><span class="tok-comment">// Predicates</span>
</span>
<span class="line" id="L370"><span class="tok-kw">const</span> TokenPredicate = *<span class="tok-kw">const</span> <span class="tok-kw">fn</span> (Token) <span class="tok-type">bool</span>;</span>
<span class="line" id="L371"></span>
<span class="line" id="L372"><span class="tok-kw">fn</span> <span class="tok-fn">isAHLetter</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L373"> <span class="tok-kw">return</span> token.ty == .aletter <span class="tok-kw">or</span> token.ty == .hletter;</span>
<span class="line" id="L374">}</span>
<span class="line" id="L375"></span>
<span class="line" id="L376"><span class="tok-kw">fn</span> <span class="tok-fn">isAlphaNum</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L377"> <span class="tok-kw">return</span> isAHLetter(token) <span class="tok-kw">or</span> isNumeric(token);</span>
<span class="line" id="L378">}</span>
<span class="line" id="L379"></span>
<span class="line" id="L380"><span class="tok-kw">fn</span> <span class="tok-fn">isBreaker</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L381"> <span class="tok-kw">return</span> token.ty == .newline <span class="tok-kw">or</span> token.ty == .cr <span class="tok-kw">or</span> token.ty == .lf;</span>
<span class="line" id="L382">}</span>
<span class="line" id="L383"></span>
<span class="line" id="L384"><span class="tok-kw">fn</span> <span class="tok-fn">isIgnorable</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L385"> <span class="tok-kw">return</span> token.ty == .extend <span class="tok-kw">or</span> token.ty == .format <span class="tok-kw">or</span> token.ty == .zwj;</span>
<span class="line" id="L386">}</span>
<span class="line" id="L387"></span>
<span class="line" id="L388"><span class="tok-kw">fn</span> <span class="tok-fn">isMidNumLetQ</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L389"> <span class="tok-kw">return</span> token.ty == .midnumlet <span class="tok-kw">or</span> token.ty == .squote;</span>
<span class="line" id="L390">}</span>
<span class="line" id="L391"></span>
<span class="line" id="L392"><span class="tok-kw">fn</span> <span class="tok-fn">isNumeric</span>(token: Token) <span class="tok-type">bool</span> {</span>
<span class="line" id="L393"> <span class="tok-kw">return</span> token.ty == .numeric;</span>
<span class="line" id="L394">}</span>
<span class="line" id="L395"></span>
<span class="line" id="L396"><span class="tok-kw">test</span> <span class="tok-str">&quot;Segmentation comptime WordIterator&quot;</span> {</span>
<span class="line" id="L397"> <span class="tok-kw">const</span> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot;Hello&quot;</span>, <span class="tok-str">&quot; &quot;</span>, <span class="tok-str">&quot;World&quot;</span> };</span>
<span class="line" id="L398"></span>
<span class="line" id="L399"> <span class="tok-kw">comptime</span> {</span>
<span class="line" id="L400"> <span class="tok-kw">var</span> ct_iter = <span class="tok-kw">try</span> WordIterator.init(<span class="tok-str">&quot;Hello World&quot;</span>);</span>
<span class="line" id="L401"> <span class="tok-kw">var</span> i = <span class="tok-number">0</span>;</span>
<span class="line" id="L402"> <span class="tok-kw">while</span> (ct_iter.next()) |word| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L403"> <span class="tok-kw">try</span> std.testing.expect(word.eql(want[i]));</span>
<span class="line" id="L404"> }</span>
<span class="line" id="L405"> }</span>
<span class="line" id="L406">}</span>
<span class="line" id="L407"></span>
<span class="line" id="L408"><span class="tok-kw">test</span> <span class="tok-str">&quot;WB3d - Keep horizontal whitespace together.&quot;</span> {</span>
<span class="line" id="L409"> <span class="tok-kw">const</span> want = [_][]<span class="tok-kw">const</span> <span class="tok-type">u8</span>{ <span class="tok-str">&quot; &quot;</span>, <span class="tok-str">&quot;Hello&quot;</span>, <span class="tok-str">&quot; &quot;</span>, <span class="tok-str">&quot;World&quot;</span>, <span class="tok-str">&quot; &quot;</span> };</span>
<span class="line" id="L410"></span>
<span class="line" id="L411"> <span class="tok-kw">comptime</span> {</span>
<span class="line" id="L412"> <span class="tok-kw">var</span> ct_iter = <span class="tok-kw">try</span> WordIterator.init(<span class="tok-str">&quot; Hello World &quot;</span>);</span>
<span class="line" id="L413"> <span class="tok-kw">var</span> i = <span class="tok-number">0</span>;</span>
<span class="line" id="L414"> <span class="tok-kw">while</span> (ct_iter.next()) |word| : (i += <span class="tok-number">1</span>) {</span>
<span class="line" id="L415"> <span class="tok-kw">try</span> std.testing.expect(word.eql(want[i]));</span>
<span class="line" id="L416"> }</span>
<span class="line" id="L417"> }</span>
<span class="line" id="L418">}</span>
<span class="line" id="L419"></span>
</code></pre></body>
</html>

View file

@ -0,0 +1,612 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ziglyph.zig - source view</title>
<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
<link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
<style>
body{
font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
margin: 0;
line-height: 1.5;
}
pre > code {
display: block;
overflow: auto;
line-height: normal;
margin: 0em;
}
.tok-kw {
color: #333;
font-weight: bold;
}
.tok-str {
color: #d14;
}
.tok-builtin {
color: #005C7A;
}
.tok-comment {
color: #545454;
font-style: italic;
}
.tok-fn {
color: #900;
font-weight: bold;
}
.tok-null {
color: #005C5C;
}
.tok-number {
color: #005C5C;
}
.tok-type {
color: #458;
font-weight: bold;
}
pre {
counter-reset: line;
}
pre .line:before {
counter-increment: line;
content: counter(line);
display: inline-block;
padding-right: 1em;
width: 2em;
text-align: right;
color: #999;
}
.line {
width: 100%;
display: inline-block;
}
.line:target {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
background: #fafafa;
}
@media (prefers-color-scheme: dark) {
body{
background:#222;
color: #ccc;
}
pre > code {
color: #ccc;
background: #222;
border: unset;
}
.line:target {
border-top: 1px solid #444;
border-bottom: 1px solid #444;
background: #333;
}
.tok-kw {
color: #eee;
}
.tok-str {
color: #2e5;
}
.tok-builtin {
color: #ff894c;
}
.tok-comment {
color: #aa7;
}
.tok-fn {
color: #B1A0F8;
}
.tok-null {
color: #ff8080;
}
.tok-number {
color: #ff8080;
}
.tok-type {
color: #68f;
}
}
</style>
</head>
<body>
<pre><code><span class="line" id="L1"><span class="tok-comment">//! `ziglyph` is a Unicode text processing library for the Zig Programming Language.</span></span>
<span class="line" id="L2"></span>
<span class="line" id="L3"><span class="tok-kw">const</span> std = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;std&quot;</span>);</span>
<span class="line" id="L4"><span class="tok-kw">const</span> unicode = std.unicode;</span>
<span class="line" id="L5"></span>
<span class="line" id="L6"><span class="tok-comment">// Functionality by popular Unicode General Category.</span>
</span>
<span class="line" id="L7"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> letter = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;category/letter.zig&quot;</span>);</span>
<span class="line" id="L8"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> mark = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;category/mark.zig&quot;</span>);</span>
<span class="line" id="L9"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> number = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;category/number.zig&quot;</span>);</span>
<span class="line" id="L10"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> punct = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;category/punct.zig&quot;</span>);</span>
<span class="line" id="L11"></span>
<span class="line" id="L12"><span class="tok-comment">// Display width calculation.</span>
</span>
<span class="line" id="L13"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> display_width = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;display_width.zig&quot;</span>);</span>
<span class="line" id="L14"></span>
<span class="line" id="L15"><span class="tok-comment">// String segmentation.</span>
</span>
<span class="line" id="L16"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CodePoint = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;segmenter/CodePoint.zig&quot;</span>);</span>
<span class="line" id="L17"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> CodePointIterator = CodePoint.CodePointIterator;</span>
<span class="line" id="L18"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> readCodePoint = CodePoint.readCodePoint;</span>
<span class="line" id="L19"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Grapheme = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;segmenter/Grapheme.zig&quot;</span>);</span>
<span class="line" id="L20"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> GraphemeIterator = Grapheme.GraphemeIterator;</span>
<span class="line" id="L21"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> StreamingGraphemeIterator = Grapheme.StreamingGraphemeIterator;</span>
<span class="line" id="L22"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> graphemeBreak = Grapheme.graphemeBreak;</span>
<span class="line" id="L23"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Word = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;segmenter/Word.zig&quot;</span>);</span>
<span class="line" id="L24"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> WordIterator = Word.WordIterator;</span>
<span class="line" id="L25"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Sentence = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;segmenter/Sentence.zig&quot;</span>);</span>
<span class="line" id="L26"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> SentenceIterator = Sentence.SentenceIterator;</span>
<span class="line" id="L27"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> ComptimeSentenceIterator = Sentence.ComptimeSentenceIterator;</span>
<span class="line" id="L28"></span>
<span class="line" id="L29"><span class="tok-comment">// Collation</span>
</span>
<span class="line" id="L30"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Collator = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;collator/Collator.zig&quot;</span>);</span>
<span class="line" id="L31"></span>
<span class="line" id="L32"><span class="tok-comment">// Normalization</span>
</span>
<span class="line" id="L33"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> Normalizer = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;normalizer/Normalizer.zig&quot;</span>);</span>
<span class="line" id="L34"></span>
<span class="line" id="L35"><span class="tok-comment">// Auto-Generated</span>
</span>
<span class="line" id="L36"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> blocks = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/blocks.zig&quot;</span>);</span>
<span class="line" id="L37"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> case_folding = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/case_folding.zig&quot;</span>);</span>
<span class="line" id="L38"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> combining_class = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/derived_combining_class.zig&quot;</span>);</span>
<span class="line" id="L39"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> core_properties = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/derived_core_properties.zig&quot;</span>);</span>
<span class="line" id="L40"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> east_asian_width = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/derived_east_asian_width.zig&quot;</span>);</span>
<span class="line" id="L41"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> general_category = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/derived_general_category.zig&quot;</span>);</span>
<span class="line" id="L42"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> normalization_props = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/derived_normalization_props.zig&quot;</span>);</span>
<span class="line" id="L43"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> numeric_type = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/derived_numeric_type.zig&quot;</span>);</span>
<span class="line" id="L44"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> emoji = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/emoji_data.zig&quot;</span>);</span>
<span class="line" id="L45"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> grapheme_break = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/grapheme_break_property.zig&quot;</span>);</span>
<span class="line" id="L46"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> hangul = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/hangul_syllable_type.zig&quot;</span>);</span>
<span class="line" id="L47"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> lowercase = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/lower_map.zig&quot;</span>);</span>
<span class="line" id="L48"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> properties = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/prop_list.zig&quot;</span>);</span>
<span class="line" id="L49"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> sentence_break = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/sentence_break_property.zig&quot;</span>);</span>
<span class="line" id="L50"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> titlecase = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/title_map.zig&quot;</span>);</span>
<span class="line" id="L51"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> uppercase = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/upper_map.zig&quot;</span>);</span>
<span class="line" id="L52"><span class="tok-kw">pub</span> <span class="tok-kw">const</span> word_break = <span class="tok-builtin">@import</span>(<span class="tok-str">&quot;autogen/word_break_property.zig&quot;</span>);</span>
<span class="line" id="L53"></span>
<span class="line" id="L54"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAlphabetic</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L55"> <span class="tok-kw">return</span> core_properties.isAlphabetic(cp);</span>
<span class="line" id="L56">}</span>
<span class="line" id="L57"></span>
<span class="line" id="L58"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiAlphabetic</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L59"> <span class="tok-kw">return</span> (cp &gt;= <span class="tok-str">'A'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-str">'a'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>);</span>
<span class="line" id="L60">}</span>
<span class="line" id="L61"></span>
<span class="line" id="L62"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAlphaNum</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L63"> <span class="tok-kw">return</span> isAlphabetic(cp) <span class="tok-kw">or</span> isNumber(cp);</span>
<span class="line" id="L64">}</span>
<span class="line" id="L65"></span>
<span class="line" id="L66"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiAlphaNum</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L67"> <span class="tok-kw">return</span> (cp &gt;= <span class="tok-str">'A'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-str">'a'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-str">'0'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>);</span>
<span class="line" id="L68">}</span>
<span class="line" id="L69"></span>
<span class="line" id="L70"><span class="tok-comment">/// `isCased` returns true if `cp` can be lower, title, or uppercase.</span></span>
<span class="line" id="L71"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isCased</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L72"> <span class="tok-kw">return</span> letter.isCased(cp);</span>
<span class="line" id="L73">}</span>
<span class="line" id="L74"></span>
<span class="line" id="L75"><span class="tok-comment">/// `isCasedStr` returns true when all code points in `str` are either lower, title, or uppercase.</span></span>
<span class="line" id="L76"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isCasedStr</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L77"> <span class="tok-kw">var</span> iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L78"></span>
<span class="line" id="L79"> <span class="tok-kw">return</span> <span class="tok-kw">while</span> (iter.next()) |cp| {</span>
<span class="line" id="L80"> <span class="tok-kw">if</span> (!isCased(cp.code)) <span class="tok-kw">break</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L81"> } <span class="tok-kw">else</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L82">}</span>
<span class="line" id="L83"></span>
<span class="line" id="L84"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph isCasedStr&quot;</span> {</span>
<span class="line" id="L85"> <span class="tok-kw">try</span> std.testing.expect(isCasedStr(<span class="tok-str">&quot;abc&quot;</span>));</span>
<span class="line" id="L86"> <span class="tok-kw">try</span> std.testing.expect(!isCasedStr(<span class="tok-str">&quot;abc123&quot;</span>));</span>
<span class="line" id="L87"> <span class="tok-kw">try</span> std.testing.expect(!isCasedStr(<span class="tok-str">&quot;123&quot;</span>));</span>
<span class="line" id="L88">}</span>
<span class="line" id="L89"></span>
<span class="line" id="L90"><span class="tok-comment">/// `isDecimal` detects all Unicode decimal numbers.</span></span>
<span class="line" id="L91"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isDecimal</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L92"> <span class="tok-kw">return</span> number.isDecimal(cp);</span>
<span class="line" id="L93">}</span>
<span class="line" id="L94"></span>
<span class="line" id="L95"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L96"> <span class="tok-kw">return</span> number.isDigit(cp);</span>
<span class="line" id="L97">}</span>
<span class="line" id="L98"></span>
<span class="line" id="L99"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L100"> <span class="tok-kw">return</span> cp &gt;= <span class="tok-str">'0'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>;</span>
<span class="line" id="L101">}</span>
<span class="line" id="L102"></span>
<span class="line" id="L103"><span class="tok-comment">/// `isGraphic` detects any code point that can be represented graphically, including spaces.</span></span>
<span class="line" id="L104"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isGraphic</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L105"> <span class="tok-kw">return</span> isPrint(cp) <span class="tok-kw">or</span> isWhiteSpace(cp);</span>
<span class="line" id="L106">}</span>
<span class="line" id="L107"></span>
<span class="line" id="L108"><span class="tok-comment">// `isHexDigit` detects hexadecimal code points.</span>
</span>
<span class="line" id="L109"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isHexDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L110"> <span class="tok-kw">return</span> number.isHexDigit(cp);</span>
<span class="line" id="L111">}</span>
<span class="line" id="L112"></span>
<span class="line" id="L113"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiHexDigit</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L114"> <span class="tok-kw">return</span> (cp &gt;= <span class="tok-str">'a'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'f'</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-str">'A'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'F'</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-str">'0'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>);</span>
<span class="line" id="L115">}</span>
<span class="line" id="L116"></span>
<span class="line" id="L117"><span class="tok-comment">/// `isPrint` detects any code point that can be printed, excluding spaces.</span></span>
<span class="line" id="L118"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isPrint</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L119"> <span class="tok-kw">return</span> isAlphaNum(cp) <span class="tok-kw">or</span> isMark(cp) <span class="tok-kw">or</span> isPunct(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L120"> isSymbol(cp) <span class="tok-kw">or</span> isWhiteSpace(cp);</span>
<span class="line" id="L121">}</span>
<span class="line" id="L122"></span>
<span class="line" id="L123"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiPrint</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L124"> <span class="tok-kw">return</span> std.ascii.isPrint(<span class="tok-builtin">@intCast</span>(cp));</span>
<span class="line" id="L125">}</span>
<span class="line" id="L126"></span>
<span class="line" id="L127"><span class="tok-comment">/// `isControl` detects control characters.</span></span>
<span class="line" id="L128"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isControl</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L129"> <span class="tok-kw">return</span> general_category.isControl(cp);</span>
<span class="line" id="L130">}</span>
<span class="line" id="L131"></span>
<span class="line" id="L132"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiControl</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L133"> <span class="tok-kw">return</span> std.ascii.isControl(<span class="tok-builtin">@intCast</span>(cp));</span>
<span class="line" id="L134">}</span>
<span class="line" id="L135"></span>
<span class="line" id="L136"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isLetter</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L137"> <span class="tok-kw">return</span> letter.isLetter(cp);</span>
<span class="line" id="L138">}</span>
<span class="line" id="L139"></span>
<span class="line" id="L140"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiLetter</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L141"> <span class="tok-kw">return</span> (cp &gt;= <span class="tok-str">'A'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) <span class="tok-kw">or</span> (cp &gt;= <span class="tok-str">'a'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>);</span>
<span class="line" id="L142">}</span>
<span class="line" id="L143"></span>
<span class="line" id="L144"><span class="tok-comment">/// `isLower` detects code points that are lowercase.</span></span>
<span class="line" id="L145"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isLower</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L146"> <span class="tok-kw">return</span> letter.isLower(cp);</span>
<span class="line" id="L147">}</span>
<span class="line" id="L148"></span>
<span class="line" id="L149"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiLower</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L150"> <span class="tok-kw">return</span> cp &gt;= <span class="tok-str">'a'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>;</span>
<span class="line" id="L151">}</span>
<span class="line" id="L152"></span>
<span class="line" id="L153"><span class="tok-comment">/// `isLowerStr` returns true when all code points in `s` are lowercase.</span></span>
<span class="line" id="L154"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isLowerStr</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L155"> <span class="tok-kw">var</span> iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L156"></span>
<span class="line" id="L157"> <span class="tok-kw">return</span> <span class="tok-kw">while</span> (iter.next()) |cp| {</span>
<span class="line" id="L158"> <span class="tok-kw">if</span> (isCased(cp.code) <span class="tok-kw">and</span> !isLower(cp.code)) <span class="tok-kw">break</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L159"> } <span class="tok-kw">else</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L160">}</span>
<span class="line" id="L161"></span>
<span class="line" id="L162"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph isLowerStr&quot;</span> {</span>
<span class="line" id="L163"> <span class="tok-kw">try</span> std.testing.expect(isLowerStr(<span class="tok-str">&quot;abc&quot;</span>));</span>
<span class="line" id="L164"> <span class="tok-kw">try</span> std.testing.expect(isLowerStr(<span class="tok-str">&quot;abc123&quot;</span>));</span>
<span class="line" id="L165"> <span class="tok-kw">try</span> std.testing.expect(!isLowerStr(<span class="tok-str">&quot;Abc123&quot;</span>));</span>
<span class="line" id="L166">}</span>
<span class="line" id="L167"></span>
<span class="line" id="L168"><span class="tok-comment">/// `isMark` detects Unicode marks (combining, spacing, etc.)</span></span>
<span class="line" id="L169"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isMark</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L170"> <span class="tok-kw">return</span> mark.isMark(cp);</span>
<span class="line" id="L171">}</span>
<span class="line" id="L172"></span>
<span class="line" id="L173"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isNumber</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L174"> <span class="tok-kw">return</span> number.isNumber(cp);</span>
<span class="line" id="L175">}</span>
<span class="line" id="L176"></span>
<span class="line" id="L177"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiNumber</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L178"> <span class="tok-kw">return</span> cp &gt;= <span class="tok-str">'0'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'9'</span>;</span>
<span class="line" id="L179">}</span>
<span class="line" id="L180"></span>
<span class="line" id="L181"><span class="tok-comment">/// `isPunct` detects punctuation characters. Note some punctuation may be considered as symbols by Unicode.</span></span>
<span class="line" id="L182"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isPunct</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L183"> <span class="tok-kw">return</span> punct.isPunct(cp);</span>
<span class="line" id="L184">}</span>
<span class="line" id="L185"></span>
<span class="line" id="L186"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiPunct</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L187"> <span class="tok-kw">return</span> std.ascii.isPunct(<span class="tok-builtin">@intCast</span>(cp));</span>
<span class="line" id="L188">}</span>
<span class="line" id="L189"></span>
<span class="line" id="L190"><span class="tok-comment">/// `isWhiteSpace` detects code points that have the Unicode *WhiteSpace* property.</span></span>
<span class="line" id="L191"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isWhiteSpace</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L192"> <span class="tok-kw">return</span> properties.isWhiteSpace(cp);</span>
<span class="line" id="L193">}</span>
<span class="line" id="L194"></span>
<span class="line" id="L195"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiWhiteSpace</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L196"> <span class="tok-kw">return</span> std.ascii.isSpace(<span class="tok-builtin">@intCast</span>(cp));</span>
<span class="line" id="L197">}</span>
<span class="line" id="L198"></span>
<span class="line" id="L199"><span class="tok-comment">// `isSymbol` detects symbols which may include code points commonly considered to be punctuation.</span>
</span>
<span class="line" id="L200"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isSymbol</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L201"> <span class="tok-kw">return</span> general_category.isMathSymbol(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L202"> general_category.isCurrencySymbol(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L203"> general_category.isModifierSymbol(cp) <span class="tok-kw">or</span></span>
<span class="line" id="L204"> general_category.isOtherSymbol(cp);</span>
<span class="line" id="L205">}</span>
<span class="line" id="L206"></span>
<span class="line" id="L207"><span class="tok-comment">/// `isTitle` detects code points in titlecase, which may be different than uppercase.</span></span>
<span class="line" id="L208"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isTitle</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L209"> <span class="tok-kw">return</span> letter.isTitle(cp);</span>
<span class="line" id="L210">}</span>
<span class="line" id="L211"></span>
<span class="line" id="L212"><span class="tok-comment">/// `isUpper` detects code points in uppercase.</span></span>
<span class="line" id="L213"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isUpper</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L214"> <span class="tok-kw">return</span> letter.isUpper(cp);</span>
<span class="line" id="L215">}</span>
<span class="line" id="L216"></span>
<span class="line" id="L217"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isAsciiUpper</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L218"> <span class="tok-kw">return</span> cp &gt;= <span class="tok-str">'A'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>;</span>
<span class="line" id="L219">}</span>
<span class="line" id="L220"></span>
<span class="line" id="L221"><span class="tok-comment">/// `isUpperStr` returns true when all code points in `str` are uppercase.</span></span>
<span class="line" id="L222"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">isUpperStr</span>(str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) <span class="tok-type">bool</span> {</span>
<span class="line" id="L223"> <span class="tok-kw">var</span> iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L224"></span>
<span class="line" id="L225"> <span class="tok-kw">return</span> <span class="tok-kw">while</span> (iter.next()) |cp| {</span>
<span class="line" id="L226"> <span class="tok-kw">if</span> (isCased(cp.code) <span class="tok-kw">and</span> !isUpper(cp.code)) <span class="tok-kw">break</span> <span class="tok-null">false</span>;</span>
<span class="line" id="L227"> } <span class="tok-kw">else</span> <span class="tok-null">true</span>;</span>
<span class="line" id="L228">}</span>
<span class="line" id="L229"></span>
<span class="line" id="L230"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph isUpperStr&quot;</span> {</span>
<span class="line" id="L231"> <span class="tok-kw">try</span> std.testing.expect(isUpperStr(<span class="tok-str">&quot;ABC&quot;</span>));</span>
<span class="line" id="L232"> <span class="tok-kw">try</span> std.testing.expect(isUpperStr(<span class="tok-str">&quot;ABC123&quot;</span>));</span>
<span class="line" id="L233"> <span class="tok-kw">try</span> std.testing.expect(!isUpperStr(<span class="tok-str">&quot;abc123&quot;</span>));</span>
<span class="line" id="L234">}</span>
<span class="line" id="L235"></span>
<span class="line" id="L236"><span class="tok-comment">/// `toLower` returns the lowercase code point for the given code point. It returns the same</span></span>
<span class="line" id="L237"><span class="tok-comment">/// code point given if no mapping exists.</span></span>
<span class="line" id="L238"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toLower</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L239"> <span class="tok-kw">return</span> letter.toLower(cp);</span>
<span class="line" id="L240">}</span>
<span class="line" id="L241"></span>
<span class="line" id="L242"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toAsciiLower</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L243"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (cp &gt;= <span class="tok-str">'A'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'Z'</span>) cp ^ <span class="tok-number">32</span> <span class="tok-kw">else</span> cp;</span>
<span class="line" id="L244">}</span>
<span class="line" id="L245"></span>
<span class="line" id="L246"><span class="tok-comment">/// `toCaseFoldStr` returns the case folded version of `str`. Caller must free returned memory.</span></span>
<span class="line" id="L247"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toCaseFoldStr</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L248"> <span class="tok-kw">var</span> result = std.ArrayList(<span class="tok-type">u8</span>).init(allocator);</span>
<span class="line" id="L249"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L250"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L251"> <span class="tok-kw">var</span> iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L252"></span>
<span class="line" id="L253"> <span class="tok-kw">while</span> (iter.next()) |cp| {</span>
<span class="line" id="L254"> <span class="tok-kw">const</span> cf = letter.toCaseFold(cp.code);</span>
<span class="line" id="L255"> <span class="tok-kw">for</span> (cf) |cfcp| {</span>
<span class="line" id="L256"> <span class="tok-kw">if</span> (cfcp == <span class="tok-number">0</span>) <span class="tok-kw">break</span>;</span>
<span class="line" id="L257"> <span class="tok-kw">const</span> len = <span class="tok-kw">try</span> unicode.utf8Encode(cfcp, &amp;buf);</span>
<span class="line" id="L258"> <span class="tok-kw">try</span> result.appendSlice(buf[<span class="tok-number">0</span>..len]);</span>
<span class="line" id="L259"> }</span>
<span class="line" id="L260"> }</span>
<span class="line" id="L261"></span>
<span class="line" id="L262"> <span class="tok-kw">return</span> result.toOwnedSlice();</span>
<span class="line" id="L263">}</span>
<span class="line" id="L264"></span>
<span class="line" id="L265"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph toCaseFoldStr&quot;</span> {</span>
<span class="line" id="L266"> <span class="tok-kw">var</span> allocator = std.testing.allocator;</span>
<span class="line" id="L267"> <span class="tok-kw">const</span> got = <span class="tok-kw">try</span> toCaseFoldStr(allocator, <span class="tok-str">&quot;AbC123\u{0390}&quot;</span>);</span>
<span class="line" id="L268"> <span class="tok-kw">defer</span> allocator.free(got);</span>
<span class="line" id="L269"> <span class="tok-kw">try</span> std.testing.expect(std.mem.eql(<span class="tok-type">u8</span>, <span class="tok-str">&quot;abc123\u{03B9}\u{0308}\u{0301}&quot;</span>, got));</span>
<span class="line" id="L270">}</span>
<span class="line" id="L271"></span>
<span class="line" id="L272"><span class="tok-comment">/// `toLowerStr` returns the lowercase version of `s`. Caller must free returned memory with `allocator`.</span></span>
<span class="line" id="L273"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toLowerStr</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L274"> <span class="tok-kw">var</span> result = std.ArrayList(<span class="tok-type">u8</span>).init(allocator);</span>
<span class="line" id="L275"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L276"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L277"> <span class="tok-kw">var</span> iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L278"></span>
<span class="line" id="L279"> <span class="tok-kw">while</span> (iter.next()) |cp| {</span>
<span class="line" id="L280"> <span class="tok-kw">const</span> len = <span class="tok-kw">try</span> unicode.utf8Encode(toLower(cp.code), &amp;buf);</span>
<span class="line" id="L281"> <span class="tok-kw">try</span> result.appendSlice(buf[<span class="tok-number">0</span>..len]);</span>
<span class="line" id="L282"> }</span>
<span class="line" id="L283"></span>
<span class="line" id="L284"> <span class="tok-kw">return</span> result.toOwnedSlice();</span>
<span class="line" id="L285">}</span>
<span class="line" id="L286"></span>
<span class="line" id="L287"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph toLowerStr&quot;</span> {</span>
<span class="line" id="L288"> <span class="tok-kw">var</span> allocator = std.testing.allocator;</span>
<span class="line" id="L289"> <span class="tok-kw">const</span> got = <span class="tok-kw">try</span> toLowerStr(allocator, <span class="tok-str">&quot;AbC123&quot;</span>);</span>
<span class="line" id="L290"> <span class="tok-kw">defer</span> allocator.free(got);</span>
<span class="line" id="L291"> <span class="tok-kw">try</span> std.testing.expect(std.mem.eql(<span class="tok-type">u8</span>, <span class="tok-str">&quot;abc123&quot;</span>, got));</span>
<span class="line" id="L292">}</span>
<span class="line" id="L293"></span>
<span class="line" id="L294"><span class="tok-comment">/// `toTitle` returns the titlecase code point for the given code point. It returns the same</span></span>
<span class="line" id="L295"><span class="tok-comment">/// code point given if no mapping exists.</span></span>
<span class="line" id="L296"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toTitle</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L297"> <span class="tok-kw">return</span> letter.toTitle(cp);</span>
<span class="line" id="L298">}</span>
<span class="line" id="L299"></span>
<span class="line" id="L300"><span class="tok-comment">/// `toTitleStr` returns the titlecase version of `str`. Caller must free returned memory with `allocator`.</span></span>
<span class="line" id="L301"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toTitleStr</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L302"> <span class="tok-kw">var</span> words = <span class="tok-kw">try</span> WordIterator.init(str);</span>
<span class="line" id="L303"> <span class="tok-kw">var</span> result = std.ArrayList(<span class="tok-type">u8</span>).init(allocator);</span>
<span class="line" id="L304"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L305"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L306"></span>
<span class="line" id="L307"> <span class="tok-kw">while</span> (words.next()) |word| {</span>
<span class="line" id="L308"> <span class="tok-kw">var</span> code_points = CodePointIterator{ .bytes = word.bytes };</span>
<span class="line" id="L309"> <span class="tok-kw">var</span> got_f = <span class="tok-null">false</span>;</span>
<span class="line" id="L310"></span>
<span class="line" id="L311"> <span class="tok-kw">while</span> (code_points.next()) |cp| {</span>
<span class="line" id="L312"> <span class="tok-kw">var</span> len: <span class="tok-type">usize</span> = <span class="tok-number">0</span>;</span>
<span class="line" id="L313"></span>
<span class="line" id="L314"> <span class="tok-kw">if</span> (!got_f <span class="tok-kw">and</span> isCased(cp.code)) {</span>
<span class="line" id="L315"> <span class="tok-comment">// First cased is titlecase.</span>
</span>
<span class="line" id="L316"> len = <span class="tok-kw">try</span> unicode.utf8Encode(toTitle(cp.code), &amp;buf);</span>
<span class="line" id="L317"> got_f = <span class="tok-null">true</span>;</span>
<span class="line" id="L318"> } <span class="tok-kw">else</span> <span class="tok-kw">if</span> (isCased(cp.code)) {</span>
<span class="line" id="L319"> <span class="tok-comment">// Subsequent cased are lowercase.</span>
</span>
<span class="line" id="L320"> len = <span class="tok-kw">try</span> unicode.utf8Encode(toLower(cp.code), &amp;buf);</span>
<span class="line" id="L321"> } <span class="tok-kw">else</span> {</span>
<span class="line" id="L322"> <span class="tok-comment">// Uncased remain the same.</span>
</span>
<span class="line" id="L323"> len = <span class="tok-kw">try</span> unicode.utf8Encode(cp.code, &amp;buf);</span>
<span class="line" id="L324"> }</span>
<span class="line" id="L325"></span>
<span class="line" id="L326"> <span class="tok-kw">try</span> result.appendSlice(buf[<span class="tok-number">0</span>..len]);</span>
<span class="line" id="L327"> }</span>
<span class="line" id="L328"> }</span>
<span class="line" id="L329"></span>
<span class="line" id="L330"> <span class="tok-kw">return</span> result.toOwnedSlice();</span>
<span class="line" id="L331">}</span>
<span class="line" id="L332"></span>
<span class="line" id="L333"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph toTitleStr&quot;</span> {</span>
<span class="line" id="L334"> <span class="tok-kw">var</span> allocator = std.testing.allocator;</span>
<span class="line" id="L335"> <span class="tok-kw">const</span> got = <span class="tok-kw">try</span> toTitleStr(allocator, <span class="tok-str">&quot;the aBc123 broWn. fox&quot;</span>);</span>
<span class="line" id="L336"> <span class="tok-kw">defer</span> allocator.free(got);</span>
<span class="line" id="L337"> <span class="tok-kw">try</span> std.testing.expectEqualStrings(<span class="tok-str">&quot;The Abc123 Brown. Fox&quot;</span>, got);</span>
<span class="line" id="L338">}</span>
<span class="line" id="L339"></span>
<span class="line" id="L340"><span class="tok-comment">/// `toUpper` returns the uppercase code point for the given code point. It returns the same</span></span>
<span class="line" id="L341"><span class="tok-comment">/// code point given if no mapping exists.</span></span>
<span class="line" id="L342"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toUpper</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L343"> <span class="tok-kw">return</span> letter.toUpper(cp);</span>
<span class="line" id="L344">}</span>
<span class="line" id="L345"></span>
<span class="line" id="L346"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toAsciiUpper</span>(cp: <span class="tok-type">u21</span>) <span class="tok-type">u21</span> {</span>
<span class="line" id="L347"> <span class="tok-kw">return</span> <span class="tok-kw">if</span> (cp &gt;= <span class="tok-str">'a'</span> <span class="tok-kw">and</span> cp &lt;= <span class="tok-str">'z'</span>) cp ^ <span class="tok-number">32</span> <span class="tok-kw">else</span> cp;</span>
<span class="line" id="L348">}</span>
<span class="line" id="L349"></span>
<span class="line" id="L350"><span class="tok-comment">/// `toUpperStr` returns the uppercase version of `str`. Caller must free returned memory with `allocator`.</span></span>
<span class="line" id="L351"><span class="tok-kw">pub</span> <span class="tok-kw">fn</span> <span class="tok-fn">toUpperStr</span>(allocator: std.mem.Allocator, str: []<span class="tok-kw">const</span> <span class="tok-type">u8</span>) ![]<span class="tok-type">u8</span> {</span>
<span class="line" id="L352"> <span class="tok-kw">var</span> result = std.ArrayList(<span class="tok-type">u8</span>).init(allocator);</span>
<span class="line" id="L353"> <span class="tok-kw">defer</span> result.deinit();</span>
<span class="line" id="L354"> <span class="tok-kw">var</span> buf: [<span class="tok-number">4</span>]<span class="tok-type">u8</span> = <span class="tok-null">undefined</span>;</span>
<span class="line" id="L355"> <span class="tok-kw">var</span> iter = CodePointIterator{ .bytes = str };</span>
<span class="line" id="L356"></span>
<span class="line" id="L357"> <span class="tok-kw">while</span> (iter.next()) |cp| {</span>
<span class="line" id="L358"> <span class="tok-kw">const</span> len = <span class="tok-kw">try</span> unicode.utf8Encode(toUpper(cp.code), &amp;buf);</span>
<span class="line" id="L359"> <span class="tok-kw">try</span> result.appendSlice(buf[<span class="tok-number">0</span>..len]);</span>
<span class="line" id="L360"> }</span>
<span class="line" id="L361"></span>
<span class="line" id="L362"> <span class="tok-kw">return</span> result.toOwnedSlice();</span>
<span class="line" id="L363">}</span>
<span class="line" id="L364"></span>
<span class="line" id="L365"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph toUpperStr&quot;</span> {</span>
<span class="line" id="L366"> <span class="tok-kw">var</span> allocator = std.testing.allocator;</span>
<span class="line" id="L367"> <span class="tok-kw">const</span> got = <span class="tok-kw">try</span> toUpperStr(allocator, <span class="tok-str">&quot;aBc123&quot;</span>);</span>
<span class="line" id="L368"> <span class="tok-kw">defer</span> allocator.free(got);</span>
<span class="line" id="L369"> <span class="tok-kw">try</span> std.testing.expect(std.mem.eql(<span class="tok-type">u8</span>, <span class="tok-str">&quot;ABC123&quot;</span>, got));</span>
<span class="line" id="L370">}</span>
<span class="line" id="L371"></span>
<span class="line" id="L372"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph ASCII methods&quot;</span> {</span>
<span class="line" id="L373"> <span class="tok-kw">const</span> z = <span class="tok-str">'F'</span>;</span>
<span class="line" id="L374"> <span class="tok-kw">try</span> std.testing.expect(isAsciiAlphabetic(z));</span>
<span class="line" id="L375"> <span class="tok-kw">try</span> std.testing.expect(isAsciiAlphaNum(z));</span>
<span class="line" id="L376"> <span class="tok-kw">try</span> std.testing.expect(isAsciiHexDigit(z));</span>
<span class="line" id="L377"> <span class="tok-kw">try</span> std.testing.expect(isAsciiPrint(z));</span>
<span class="line" id="L378"> <span class="tok-kw">try</span> std.testing.expect(isAsciiUpper(z));</span>
<span class="line" id="L379"> <span class="tok-kw">try</span> std.testing.expect(!isAsciiControl(z));</span>
<span class="line" id="L380"> <span class="tok-kw">try</span> std.testing.expect(!isAsciiDigit(z));</span>
<span class="line" id="L381"> <span class="tok-kw">try</span> std.testing.expect(!isAsciiNumber(z));</span>
<span class="line" id="L382"> <span class="tok-kw">try</span> std.testing.expect(!isAsciiLower(z));</span>
<span class="line" id="L383"> <span class="tok-kw">try</span> std.testing.expectEqual(toAsciiLower(z), <span class="tok-str">'f'</span>);</span>
<span class="line" id="L384"> <span class="tok-kw">try</span> std.testing.expectEqual(toAsciiUpper(<span class="tok-str">'a'</span>), <span class="tok-str">'A'</span>);</span>
<span class="line" id="L385"> <span class="tok-kw">try</span> std.testing.expect(isAsciiLower(toAsciiLower(z)));</span>
<span class="line" id="L386">}</span>
<span class="line" id="L387"></span>
<span class="line" id="L388"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph struct&quot;</span> {</span>
<span class="line" id="L389"> <span class="tok-kw">const</span> z = <span class="tok-str">'z'</span>;</span>
<span class="line" id="L390"> <span class="tok-kw">try</span> std.testing.expect(isAlphaNum(z));</span>
<span class="line" id="L391"> <span class="tok-kw">try</span> std.testing.expect(!isControl(z));</span>
<span class="line" id="L392"> <span class="tok-kw">try</span> std.testing.expect(!isDecimal(z));</span>
<span class="line" id="L393"> <span class="tok-kw">try</span> std.testing.expect(!isDigit(z));</span>
<span class="line" id="L394"> <span class="tok-kw">try</span> std.testing.expect(!isHexDigit(z));</span>
<span class="line" id="L395"> <span class="tok-kw">try</span> std.testing.expect(isGraphic(z));</span>
<span class="line" id="L396"> <span class="tok-kw">try</span> std.testing.expect(isLetter(z));</span>
<span class="line" id="L397"> <span class="tok-kw">try</span> std.testing.expect(isLower(z));</span>
<span class="line" id="L398"> <span class="tok-kw">try</span> std.testing.expect(!isMark(z));</span>
<span class="line" id="L399"> <span class="tok-kw">try</span> std.testing.expect(!isNumber(z));</span>
<span class="line" id="L400"> <span class="tok-kw">try</span> std.testing.expect(isPrint(z));</span>
<span class="line" id="L401"> <span class="tok-kw">try</span> std.testing.expect(!isPunct(z));</span>
<span class="line" id="L402"> <span class="tok-kw">try</span> std.testing.expect(!isWhiteSpace(z));</span>
<span class="line" id="L403"> <span class="tok-kw">try</span> std.testing.expect(!isSymbol(z));</span>
<span class="line" id="L404"> <span class="tok-kw">try</span> std.testing.expect(!isTitle(z));</span>
<span class="line" id="L405"> <span class="tok-kw">try</span> std.testing.expect(!isUpper(z));</span>
<span class="line" id="L406"> <span class="tok-kw">const</span> uz = toUpper(z);</span>
<span class="line" id="L407"> <span class="tok-kw">try</span> std.testing.expect(isUpper(uz));</span>
<span class="line" id="L408"> <span class="tok-kw">try</span> std.testing.expectEqual(uz, <span class="tok-str">'Z'</span>);</span>
<span class="line" id="L409"> <span class="tok-kw">const</span> lz = toLower(uz);</span>
<span class="line" id="L410"> <span class="tok-kw">try</span> std.testing.expect(isLower(lz));</span>
<span class="line" id="L411"> <span class="tok-kw">try</span> std.testing.expectEqual(lz, <span class="tok-str">'z'</span>);</span>
<span class="line" id="L412"> <span class="tok-kw">const</span> tz = toTitle(lz);</span>
<span class="line" id="L413"> <span class="tok-kw">try</span> std.testing.expect(isUpper(tz));</span>
<span class="line" id="L414"> <span class="tok-kw">try</span> std.testing.expectEqual(tz, <span class="tok-str">'Z'</span>);</span>
<span class="line" id="L415">}</span>
<span class="line" id="L416"></span>
<span class="line" id="L417"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph isGraphic&quot;</span> {</span>
<span class="line" id="L418"> <span class="tok-kw">try</span> std.testing.expect(isGraphic(<span class="tok-str">'A'</span>));</span>
<span class="line" id="L419"> <span class="tok-kw">try</span> std.testing.expect(isGraphic(<span class="tok-str">'\u{20E4}'</span>));</span>
<span class="line" id="L420"> <span class="tok-kw">try</span> std.testing.expect(isGraphic(<span class="tok-str">'1'</span>));</span>
<span class="line" id="L421"> <span class="tok-kw">try</span> std.testing.expect(isGraphic(<span class="tok-str">'?'</span>));</span>
<span class="line" id="L422"> <span class="tok-kw">try</span> std.testing.expect(isGraphic(<span class="tok-str">' '</span>));</span>
<span class="line" id="L423"> <span class="tok-kw">try</span> std.testing.expect(isGraphic(<span class="tok-str">'='</span>));</span>
<span class="line" id="L424"> <span class="tok-kw">try</span> std.testing.expect(!isGraphic(<span class="tok-str">'\u{0003}'</span>));</span>
<span class="line" id="L425">}</span>
<span class="line" id="L426"></span>
<span class="line" id="L427"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph isHexDigit&quot;</span> {</span>
<span class="line" id="L428"> <span class="tok-kw">var</span> cp: <span class="tok-type">u21</span> = <span class="tok-str">'0'</span>;</span>
<span class="line" id="L429"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'9'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L430"> <span class="tok-kw">try</span> std.testing.expect(isHexDigit(cp));</span>
<span class="line" id="L431"> }</span>
<span class="line" id="L432"></span>
<span class="line" id="L433"> cp = <span class="tok-str">'A'</span>;</span>
<span class="line" id="L434"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'F'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L435"> <span class="tok-kw">try</span> std.testing.expect(isHexDigit(cp));</span>
<span class="line" id="L436"> }</span>
<span class="line" id="L437"></span>
<span class="line" id="L438"> cp = <span class="tok-str">'a'</span>;</span>
<span class="line" id="L439"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'f'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L440"> <span class="tok-kw">try</span> std.testing.expect(isHexDigit(cp));</span>
<span class="line" id="L441"> }</span>
<span class="line" id="L442"></span>
<span class="line" id="L443"> <span class="tok-kw">try</span> std.testing.expect(!isHexDigit(<span class="tok-str">'\u{0003}'</span>));</span>
<span class="line" id="L444"> <span class="tok-kw">try</span> std.testing.expect(!isHexDigit(<span class="tok-str">'Z'</span>));</span>
<span class="line" id="L445">}</span>
<span class="line" id="L446"></span>
<span class="line" id="L447"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph isPrint&quot;</span> {</span>
<span class="line" id="L448"> <span class="tok-kw">try</span> std.testing.expect(isPrint(<span class="tok-str">'A'</span>));</span>
<span class="line" id="L449"> <span class="tok-kw">try</span> std.testing.expect(isPrint(<span class="tok-str">'\u{20E4}'</span>));</span>
<span class="line" id="L450"> <span class="tok-kw">try</span> std.testing.expect(isPrint(<span class="tok-str">'1'</span>));</span>
<span class="line" id="L451"> <span class="tok-kw">try</span> std.testing.expect(isPrint(<span class="tok-str">'?'</span>));</span>
<span class="line" id="L452"> <span class="tok-kw">try</span> std.testing.expect(isPrint(<span class="tok-str">'='</span>));</span>
<span class="line" id="L453"> <span class="tok-kw">try</span> std.testing.expect(isPrint(<span class="tok-str">' '</span>));</span>
<span class="line" id="L454"> <span class="tok-kw">try</span> std.testing.expect(isPrint(<span class="tok-str">'\t'</span>));</span>
<span class="line" id="L455"> <span class="tok-kw">try</span> std.testing.expect(!isPrint(<span class="tok-str">'\u{0003}'</span>));</span>
<span class="line" id="L456">}</span>
<span class="line" id="L457"></span>
<span class="line" id="L458"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph isAlphaNum&quot;</span> {</span>
<span class="line" id="L459"> <span class="tok-kw">var</span> cp: <span class="tok-type">u21</span> = <span class="tok-str">'0'</span>;</span>
<span class="line" id="L460"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'9'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L461"> <span class="tok-kw">try</span> std.testing.expect(isAlphaNum(cp));</span>
<span class="line" id="L462"> }</span>
<span class="line" id="L463"></span>
<span class="line" id="L464"> cp = <span class="tok-str">'a'</span>;</span>
<span class="line" id="L465"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'z'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L466"> <span class="tok-kw">try</span> std.testing.expect(isAlphaNum(cp));</span>
<span class="line" id="L467"> }</span>
<span class="line" id="L468"></span>
<span class="line" id="L469"> cp = <span class="tok-str">'A'</span>;</span>
<span class="line" id="L470"> <span class="tok-kw">while</span> (cp &lt;= <span class="tok-str">'Z'</span>) : (cp += <span class="tok-number">1</span>) {</span>
<span class="line" id="L471"> <span class="tok-kw">try</span> std.testing.expect(isAlphaNum(cp));</span>
<span class="line" id="L472"> }</span>
<span class="line" id="L473"></span>
<span class="line" id="L474"> <span class="tok-kw">try</span> std.testing.expect(!isAlphaNum(<span class="tok-str">'='</span>));</span>
<span class="line" id="L475">}</span>
<span class="line" id="L476"></span>
<span class="line" id="L477"><span class="tok-kw">test</span> <span class="tok-str">&quot;ziglyph isControl&quot;</span> {</span>
<span class="line" id="L478"> <span class="tok-kw">try</span> std.testing.expect(isControl(<span class="tok-str">'\t'</span>));</span>
<span class="line" id="L479"> <span class="tok-kw">try</span> std.testing.expect(isControl(<span class="tok-str">'\u{0008}'</span>));</span>
<span class="line" id="L480"> <span class="tok-kw">try</span> std.testing.expect(isControl(<span class="tok-str">'\u{0012}'</span>));</span>
<span class="line" id="L481"> <span class="tok-kw">try</span> std.testing.expect(isControl(<span class="tok-str">'\n'</span>));</span>
<span class="line" id="L482"> <span class="tok-kw">try</span> std.testing.expect(isControl(<span class="tok-str">'\r'</span>));</span>
<span class="line" id="L483"> <span class="tok-kw">try</span> std.testing.expect(!isControl(<span class="tok-str">'A'</span>));</span>
<span class="line" id="L484">}</span>
<span class="line" id="L485"></span>
</code></pre></body>
</html>

2147
docs/ziglexer.js Normal file

File diff suppressed because it is too large Load diff