| ... | @@ -390,6 +390,20 @@ pub const Macros = struct { | ... | @@ -390,6 +390,20 @@ pub const Macros = struct { |
| 390 | pub fn WL_CONTAINER_OF(ptr: anytype, sample: anytype, comptime member: []const u8) @TypeOf(sample) { | 390 | pub fn WL_CONTAINER_OF(ptr: anytype, sample: anytype, comptime member: []const u8) @TypeOf(sample) { |
| 391 | return @fieldParentPtr(@TypeOf(sample.*), member, ptr); | 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 | test "Macro suffix functions" { | 409 | test "Macro suffix functions" { |
| ... | @@ -430,3 +444,41 @@ test "WL_CONTAINER_OF" { | ... | @@ -430,3 +444,41 @@ test "WL_CONTAINER_OF" { |
| 430 | var ptr = Macros.WL_CONTAINER_OF(&x.b, &y, "b"); | 444 | var ptr = Macros.WL_CONTAINER_OF(&x.b, &y, "b"); |
| 431 | try testing.expectEqual(&x, ptr); | 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 | } |