Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

Ip4Address

An IPv4 address in binary memory layout.

net.Ip4Address
pub const Ip4Address = struct

File

lib/std/Io/net.zig:347

Code

pub const Ip4Address = struct {
    bytes: [4]u8,
    port: u16,

    pub fn loopback(port: u16) Ip4Address {
        return .{
            .bytes = .{ 127, 0, 0, 1 },
            .port = port,
        };
    }

    pub fn unspecified(port: u16) Ip4Address {
        return .{
            .bytes = .{ 0, 0, 0, 0 },
            .port = port,
        };
    }

    /// Converts from an IPv4-mapped IPv6 address, or returns `null`.
    pub fn fromIp6(ip6: Ip6Address) ?Ip4Address {
        return if (std.mem.eql(u8, ip6.bytes[0..12], &.{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff })) .{
            .bytes = ip6.bytes[12..].*,
            .port = ip6.port,
        } else null;
    }

    /// Given an `IpAddress`, converts it to an `Ip4Address` directly, or from
    /// an IPv4-mapped IPv6 address, or returns `null`.
    pub fn fromAny(addr: IpAddress) ?Ip6Address {
        return switch (addr) {
            .ip4 => |ip4| ip4,
            .ip6 => |ip6| fromIp6(ip6),
        };
    }

    pub const ParseError = error{
        Overflow,
        InvalidEnd,
        InvalidCharacter,
        Incomplete,
        NonCanonical,
    };

    pub fn parse(buffer: []const u8, port: u16) ParseError!Ip4Address {
        var bytes: [4]u8 = @splat(0);
        var index: u8 = 0;
        var saw_any_digits = false;
        var has_zero_prefix = false;
        for (buffer) |c| switch (c) {
            '.' => {
                if (!saw_any_digits) return error.InvalidCharacter;
                if (index == 3) return error.InvalidEnd;
                index += 1;
                saw_any_digits = false;
                has_zero_prefix = false;
            },
            '0'...'9' => {
                if (c == '0' and !saw_any_digits) {
                    has_zero_prefix = true;
                } else if (has_zero_prefix) {
                    return error.NonCanonical;
                }
                saw_any_digits = true;
                bytes[index] = try std.math.mul(u8, bytes[index], 10);
                bytes[index] = try std.math.add(u8, bytes[index], c - '0');
            },
            else => return error.InvalidCharacter,
        };
        if (index == 3 and saw_any_digits) return .{
            .bytes = bytes,
            .port = port,
        };
        return error.Incomplete;
    }

    pub fn format(a: Ip4Address, w: *Io.Writer) Io.Writer.Error!void {
        const bytes = &a.bytes;
        try w.print("{d}.{d}.{d}.{d}:{d}", .{ bytes[0], bytes[1], bytes[2], bytes[3], a.port });
    }

    pub fn eql(a: Ip4Address, b: Ip4Address) bool {
        const a_int: u32 = @bitCast(a.bytes);
        const b_int: u32 = @bitCast(b.bytes);
        return a.port == b.port and a_int == b_int;
    }
}