#include "pixel/pixel.hpp" #include namespace pixel { std::string_view describe(ChannelError error) noexcept { switch (error) { case ChannelError::non_finite: return "channel must be finite"; case ChannelError::outside_unit_interval: return "channel must be in [0,1]"; } return "unknown channel error"; } std::expected encode_channel(double linear) { if (!std::isfinite(linear)) return std::unexpected(ChannelError::non_finite); if (linear < 0.0 || linear > 1.0) return std::unexpected(ChannelError::outside_unit_interval); // Validation establishes the finite [0,255] conversion domain. return static_cast(std::lround(std::sqrt(linear) * 255.0)); } std::expected prepare_pixel(std::array linear) { std::array encoded{}; for (std::size_t channel = 0; channel < linear.size(); ++channel) { const auto result = encode_channel(linear[channel]); if (!result) return std::unexpected(PixelError{channel, result.error()}); encoded[channel] = *result; } return Pixel{encoded[0], encoded[1], encoded[2]}; } std::expected replace_pixel( Pixel& current, std::array linear) { const auto candidate = prepare_pixel(linear); if (!candidate) return std::unexpected(candidate.error()); current = *candidate; // Trivial assignment is the commit; it cannot throw. return {}; } }