// Как Zig предотвращает Undefined Behavior
// Компиляция: zig build-exe safety_demo.zig && ./safety_demo
// Без проверок: zig build-exe -OReleaseFast safety_demo.zig

const std = @import("std");

pub fn main() !void {
    const stdout = std.fs.File.stdout().deprecatedWriter();

    try stdout.print("=== Zig: безопасность с контролем ===\n\n", .{});

    // 1. Целочисленное переполнение — ошибка в safe-режиме
    try stdout.print("--- 1. Целочисленное переполнение ---\n", .{});
    const x: i32 = std.math.maxInt(i32);
    try stdout.print("maxInt(i32) = {d}\n", .{x});

    // В safe-режиме (по умолчанию): overflow → panic
    // В ReleaseFast: overflow → обёртка (как в C, но явно выбрано)
    // Для явной обёртки — операторы +% и -%
    const wrapped = x +% 1;
    try stdout.print("x +%% 1 = {d} (явная обёртка, оператор +%%)\n", .{wrapped});

    // Насыщающая арифметика: x +| 1
    const saturated = x +| 1;
    try stdout.print("x +| 1 = {d} (насыщение)\n\n", .{saturated});

    // 2. Optional вместо null
    try stdout.print("--- 2. Optional вместо null ---\n", .{});
    const arr = [_]i32{ 10, 20, 30, 40 };

    // Безопасный доступ: если индекс может быть за границей
    const index: usize = 5;
    if (index < arr.len) {
        try stdout.print("arr[{d}] = {d}\n", .{ index, arr[index] });
    } else {
        try stdout.print("Индекс {d} за границей (len = {d})\n", .{ index, arr.len });
    }

    // Optional: указатель может быть null
    var val: i32 = 42;
    var opt_ptr: ?*i32 = &val;
    if (opt_ptr) |ptr| {
        try stdout.print("opt_ptr содержит значение: {d}\n", .{ptr.*});
    }
    opt_ptr = null;
    if (opt_ptr) |_| {
        try stdout.print("Не выполнится\n", .{});
    } else {
        try stdout.print("opt_ptr = null (проверка на этапе компиляции)\n\n", .{});
    }

    // 3. Нет скрытых аллокаций, нет скрытых ошибок
    try stdout.print("--- 3. Явное управление памятью ---\n", .{});
    try stdout.print("Аллокатор передаётся явно — видно каждое выделение.\n", .{});
    try stdout.print("Нет скрытых malloc/free. Ошибка аллокации — всегда обрабатывается.\n\n", .{});

    // 4. Проверка границ
    try stdout.print("--- 4. Проверка границ ---\n", .{});
    try stdout.print("arr[4] в safe-режиме → panic: index out of bounds\n", .{});
    try stdout.print("В ReleaseFast проверки отключены (осознанный выбор).\n\n", .{});

    // 5. Отсутствие неявных преобразований типов
    try stdout.print("--- 5. Нет неявных преобразований ---\n", .{});
    const a: u8 = 200;
    const b: u16 = a; // расширение — ok
    _ = b;
    // const c: u8 = b; // ошибка компиляции: нужен @intCast
    try stdout.print("u8 → u16: неявное расширение разрешено\n", .{});
    try stdout.print("u16 → u8: требуется @intCast (явное сужение)\n\n", .{});

    try stdout.print("--- Итог ---\n", .{});
    try stdout.print("Переполнение → panic (safe) или +%% (явная обёртка)\n", .{});
    try stdout.print("Null → ?T optional (проверка компилятором)\n", .{});
    try stdout.print("Память → явный аллокатор (нет скрытых аллокаций)\n", .{});
    try stdout.print("Границы → panic в safe, отключаемы в ReleaseFast\n", .{});
    try stdout.print("Приведение типов → только явное через @intCast\n", .{});
}
