authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-01-20 23:34:41 -08:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2026-01-20 23:34:41 -08:00
log889939330ae5cff12cc54e0f0df4dc59808f1fce
treec24cd7dc3b23acf6712e2aaa6c70e18dca76f3d1
parent5507a56c5dc2d5f1264acafb094c4f7697ecd5f0

move CheckJoiners into the inner iteration


1 files changed, 83 insertions(+), 85 deletions(-)

idna.zig+83-85
...@@ -242,6 +242,13 @@ fn Validity_Criteria(...@@ -242,6 +242,13 @@ fn Validity_Criteria(
242 var it = std.unicode.Utf8View.initUnchecked(label).iterator();242 var it = std.unicode.Utf8View.initUnchecked(label).iterator();
243 var prev_ccc: u8 = 0;243 var prev_ccc: u8 = 0;
244 var prev_cp: u21 = 0;244 var prev_cp: u21 = 0;
245
246 // 8. If CheckJoiners, the label must satisify the ContextJ rules from RFC 5892 Appendix A.
247 var point_2before: ucd.unicode_data.Codepoint = ucd.unicode_data.data[0];
248 var point_before: ucd.unicode_data.Codepoint = ucd.unicode_data.data[0];
249 var zwnj_state: enum { start, dual_joining, transparent1, zwnj, transparent2, right_joining } = .start;
250 var check_zwnj_state: ?bool = null;
251
245 while (it.nextCodepointSlice()) |sl| {252 while (it.nextCodepointSlice()) |sl| {
246 const cp = std.unicode.utf8Decode(sl) catch unreachable;253 const cp = std.unicode.utf8Decode(sl) catch unreachable;
247 const status, _, _ = mappingRow(cp);254 const status, _, _ = mappingRow(cp);
...@@ -292,98 +299,89 @@ fn Validity_Criteria(...@@ -292,98 +299,89 @@ fn Validity_Criteria(
292 if (sl[0] == '-') continue;299 if (sl[0] == '-') continue;
293 return error.IDNAFailure;300 return error.IDNAFailure;
294 }301 }
295 }
296302
297 // 8. If CheckJoiners, the label must satisify the ContextJ rules from RFC 5892 Appendix A.303 const p = ucd.unicode_data.find(cp);
298 if (CheckJoiners) {
299 it.i = 0;
300 var point_2before: ucd.unicode_data.Codepoint = ucd.unicode_data.data[0];
301 var point_before: ucd.unicode_data.Codepoint = ucd.unicode_data.data[0];
302 var zwnj_state: enum { start, dual_joining, transparent1, zwnj, transparent2, right_joining } = .start;
303 var check_zwnj_state: ?bool = null;
304304
305 while (it.nextCodepointSlice()) |s| {305 if (CheckJoiners) {
306 const c = std.unicode.utf8Decode(s) catch unreachable;306 // Appendix A.1. ZERO WIDTH NON-JOINER
307 const p = ucd.unicode_data.find(c);307 if (cp == 0x200C) {
308 {308 if (check_zwnj_state == null) check_zwnj_state = true;
309 // Appendix A.1. ZERO WIDTH NON-JOINER309 if (point_before[3] == 9) check_zwnj_state = false;
310 if (c == 0x200C) {310 }
311 if (check_zwnj_state == null) check_zwnj_state = true;311 switch (zwnj_state) {
312 if (point_before[3] == 9) check_zwnj_state = false;312 .start => {
313 }313 if (Joining_Type(cp)) |t| {
314 switch (zwnj_state) {314 if (t == .L) zwnj_state = .dual_joining;
315 .start => {315 if (t == .D) zwnj_state = .dual_joining;
316 if (Joining_Type(c)) |t| {316 }
317 if (t == .L) zwnj_state = .dual_joining;317 },
318 if (t == .D) zwnj_state = .dual_joining;318 .dual_joining => {
319 }319 if (Joining_Type(cp)) |t| {
320 },320 switch (t) {
321 .dual_joining => {321 .T => zwnj_state = .transparent1,
322 if (Joining_Type(c)) |t| {322 .L, .D => {},
323 switch (t) {323 else => zwnj_state = .transparent1,
324 .T => zwnj_state = .transparent1,
325 .L, .D => {},
326 else => zwnj_state = .transparent1,
327 }
328 } else {
329 zwnj_state = .transparent1;
330 }
331 if (c == 0x200C) zwnj_state = .zwnj;
332 },
333 .transparent1 => {
334 if (c == 0x200C) {
335 zwnj_state = .zwnj;
336 } else {
337 zwnj_state = .start;
338 }324 }
339 },325 } else {
340 .zwnj => {326 zwnj_state = .transparent1;
341 if (Joining_Type(c)) |t| {327 }
342 switch (t) {328 if (cp == 0x200C) zwnj_state = .zwnj;
343 .T => zwnj_state = .transparent2,329 },
344 .R, .D => zwnj_state = .right_joining,330 .transparent1 => {
345 .L => zwnj_state = .dual_joining,331 if (cp == 0x200C) {
346 else => zwnj_state = .transparent2,332 zwnj_state = .zwnj;
347 }333 } else {
348 } else {334 zwnj_state = .start;
349 zwnj_state = .transparent2;335 }
336 },
337 .zwnj => {
338 if (Joining_Type(cp)) |t| {
339 switch (t) {
340 .T => zwnj_state = .transparent2,
341 .R, .D => zwnj_state = .right_joining,
342 .L => zwnj_state = .dual_joining,
343 else => zwnj_state = .transparent2,
350 }344 }
351 },345 } else {
352 .transparent2 => {346 zwnj_state = .transparent2;
353 if (Joining_Type(c)) |t| {347 }
354 switch (t) {348 },
355 .R, .D => zwnj_state = .right_joining,349 .transparent2 => {
356 .L => zwnj_state = .dual_joining,350 if (Joining_Type(cp)) |t| {
357 else => zwnj_state = .start,351 switch (t) {
358 }352 .R, .D => zwnj_state = .right_joining,
359 } else {353 .L => zwnj_state = .dual_joining,
360 zwnj_state = .start;354 else => zwnj_state = .start,
361 }355 }
362 },356 } else {
363 .right_joining => {357 zwnj_state = .start;
364 //rule passed358 }
365 },359 },
366 }360 .right_joining => {
367 // Appendix A.2. ZERO WIDTH JOINER361 //rule passed
368 if (c == 0x200D and point_before[3] != 9) return error.IDNAFailure;362 },
369 // Appendix A.3. MIDDLE DOT
370 if (point_before[0] == 0x00B7 and !(point_2before[0] == 0x006C and c == 0x006C)) return error.IDNAFailure;
371 // Appendix A.4. GREEK LOWER NUMERAL SIGN (KERAIA)
372 if (point_before[0] == 0x0375 and !(Script(c) == .Greek)) return error.IDNAFailure;
373 // Appendix A.5. HEBREW PUNCTUATION GERESH
374 if (c == 0x05F3 and !(Script(point_before[0]) == .Hebrew)) return error.IDNAFailure;
375 // Appendix A.6. HEBREW PUNCTUATION GERSHAYIM
376 if (c == 0x05F4 and !(Script(point_before[0]) == .Hebrew)) return error.IDNAFailure;
377 // Appendix A.7. KATAKANA MIDDLE DOT
378 if (false) return error.IDNAFailure;
379 // Appendix A.8. ARABIC-INDIC DIGITS
380 if (false) return error.IDNAFailure;
381 // Appendix A.9. EXTENDED ARABIC-INDIC DIGITS
382 if (false) return error.IDNAFailure;
383 }363 }
384 point_2before = point_before;364 // Appendix A.2. ZERO WIDTH JOINER
385 point_before = p;365 if (cp == 0x200D and point_before[3] != 9) return error.IDNAFailure;
366 // Appendix A.3. MIDDLE DOT
367 if (point_before[0] == 0x00B7 and !(point_2before[0] == 0x006C and cp == 0x006C)) return error.IDNAFailure;
368 // Appendix A.4. GREEK LOWER NUMERAL SIGN (KERAIA)
369 if (point_before[0] == 0x0375 and !(Script(cp) == .Greek)) return error.IDNAFailure;
370 // Appendix A.5. HEBREW PUNCTUATION GERESH
371 if (cp == 0x05F3 and !(Script(point_before[0]) == .Hebrew)) return error.IDNAFailure;
372 // Appendix A.6. HEBREW PUNCTUATION GERSHAYIM
373 if (cp == 0x05F4 and !(Script(point_before[0]) == .Hebrew)) return error.IDNAFailure;
374 // Appendix A.7. KATAKANA MIDDLE DOT
375 if (false) return error.IDNAFailure;
376 // Appendix A.8. ARABIC-INDIC DIGITS
377 if (false) return error.IDNAFailure;
378 // Appendix A.9. EXTENDED ARABIC-INDIC DIGITS
379 if (false) return error.IDNAFailure;
386 }380 }
381 point_2before = point_before;
382 point_before = p;
383 }
384 if (CheckJoiners) {
387 if (check_zwnj_state == true and zwnj_state != .right_joining) return error.IDNAFailure;385 if (check_zwnj_state == true and zwnj_state != .right_joining) return error.IDNAFailure;
388 }386 }
389387