| ... | ... | @@ -390,6 +390,20 @@ pub const Macros = struct { |
| 390 | 390 | pub fn WL_CONTAINER_OF(ptr: anytype, sample: anytype, comptime member: []const u8) @TypeOf(sample) { |
| 391 | 391 | return @fieldParentPtr(@TypeOf(sample.*), member, ptr); |
| 392 | 392 | } |
| 393 | |
| 394 | /// A 2-argument function-like macro defined as #define FOO(A, B) (A)(B) |
| 395 | /// could be either: cast B to A, or call A with the value B. |
| 396 | pub fn CAST_OR_CALL(a: anytype, b: anytype) switch (@typeInfo(@TypeOf(a))) { |
| 397 | .Type => a, |
| 398 | .Fn => |fn_info| fn_info.return_type orelse void, |
| 399 | else => |info| @compileError("Unexpected argument type: " ++ @tagName(info)), |
| 400 | } { |
| 401 | switch (@typeInfo(@TypeOf(a))) { |
| 402 | .Type => return cast(a, b), |
| 403 | .Fn => return a(b), |
| 404 | else => unreachable, // return type will be a compile error otherwise |
| 405 | } |
| 406 | } |
| 393 | 407 | }; |
| 394 | 408 | |
| 395 | 409 | test "Macro suffix functions" { |
| ... | ... | @@ -430,3 +444,41 @@ test "WL_CONTAINER_OF" { |
| 430 | 444 | var ptr = Macros.WL_CONTAINER_OF(&x.b, &y, "b"); |
| 431 | 445 | try testing.expectEqual(&x, ptr); |
| 432 | 446 | } |
| 447 | |
| 448 | test "CAST_OR_CALL casting" { |
| 449 | var arg = @as(c_int, 1000); |
| 450 | var casted = Macros.CAST_OR_CALL(u8, arg); |
| 451 | try testing.expectEqual(cast(u8, arg), casted); |
| 452 | |
| 453 | const S = struct { |
| 454 | x: u32 = 0, |
| 455 | }; |
| 456 | var s = S{}; |
| 457 | var casted_ptr = Macros.CAST_OR_CALL(*u8, &s); |
| 458 | try testing.expectEqual(cast(*u8, &s), casted_ptr); |
| 459 | } |
| 460 | |
| 461 | test "CAST_OR_CALL calling" { |
| 462 | const Helper = struct { |
| 463 | var last_val: bool = false; |
| 464 | fn returnsVoid(val: bool) void { |
| 465 | last_val = val; |
| 466 | } |
| 467 | fn returnsBool(f: f32) bool { |
| 468 | return f > 0; |
| 469 | } |
| 470 | fn identity(self: c_uint) c_uint { |
| 471 | return self; |
| 472 | } |
| 473 | }; |
| 474 | |
| 475 | Macros.CAST_OR_CALL(Helper.returnsVoid, true); |
| 476 | try testing.expectEqual(true, Helper.last_val); |
| 477 | Macros.CAST_OR_CALL(Helper.returnsVoid, false); |
| 478 | try testing.expectEqual(false, Helper.last_val); |
| 479 | |
| 480 | try testing.expectEqual(Helper.returnsBool(1), Macros.CAST_OR_CALL(Helper.returnsBool, @as(f32, 1))); |
| 481 | try testing.expectEqual(Helper.returnsBool(-1), Macros.CAST_OR_CALL(Helper.returnsBool, @as(f32, -1))); |
| 482 | |
| 483 | try testing.expectEqual(Helper.identity(@as(c_uint, 100)), Macros.CAST_OR_CALL(Helper.identity, @as(c_uint, 100))); |
| 484 | } |