Add UI core color parser tests
This commit is contained in:
95
src/ui_core/color.cpp
Normal file
95
src/ui_core/color.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "ui_core/color.h"
|
||||
|
||||
namespace pp::ui {
|
||||
|
||||
namespace {
|
||||
|
||||
[[nodiscard]] int hex_value(char ch) noexcept
|
||||
{
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
return ch - '0';
|
||||
}
|
||||
if (ch >= 'a' && ch <= 'f') {
|
||||
return 10 + (ch - 'a');
|
||||
}
|
||||
if (ch >= 'A' && ch <= 'F') {
|
||||
return 10 + (ch - 'A');
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<std::uint8_t> parse_hex_byte(std::string_view value) noexcept
|
||||
{
|
||||
const auto high = hex_value(value[0]);
|
||||
const auto low = hex_value(value[1]);
|
||||
if (high < 0 || low < 0) {
|
||||
return pp::foundation::Result<std::uint8_t>::failure(
|
||||
pp::foundation::Status::invalid_argument("color contains a non-hex character"));
|
||||
}
|
||||
|
||||
return pp::foundation::Result<std::uint8_t>::success(
|
||||
static_cast<std::uint8_t>((high << 4) | low));
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<std::uint8_t> parse_hex_nibble(char value) noexcept
|
||||
{
|
||||
const auto nibble = hex_value(value);
|
||||
if (nibble < 0) {
|
||||
return pp::foundation::Result<std::uint8_t>::failure(
|
||||
pp::foundation::Status::invalid_argument("color contains a non-hex character"));
|
||||
}
|
||||
|
||||
return pp::foundation::Result<std::uint8_t>::success(
|
||||
static_cast<std::uint8_t>((nibble << 4) | nibble));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pp::foundation::Result<ColorRgba8> parse_hex_color(std::string_view value) noexcept
|
||||
{
|
||||
if (value.empty()) {
|
||||
return pp::foundation::Result<ColorRgba8>::failure(
|
||||
pp::foundation::Status::invalid_argument("color must not be empty"));
|
||||
}
|
||||
|
||||
if (value.front() != '#') {
|
||||
return pp::foundation::Result<ColorRgba8>::failure(
|
||||
pp::foundation::Status::invalid_argument("color must start with #"));
|
||||
}
|
||||
|
||||
const auto hex = value.substr(1);
|
||||
if (hex.size() != 3U && hex.size() != 4U && hex.size() != 6U && hex.size() != 8U) {
|
||||
return pp::foundation::Result<ColorRgba8>::failure(
|
||||
pp::foundation::Status::invalid_argument("color must use #rgb, #rgba, #rrggbb, or #rrggbbaa"));
|
||||
}
|
||||
|
||||
ColorRgba8 color;
|
||||
if (hex.size() == 3U || hex.size() == 4U) {
|
||||
const auto r = parse_hex_nibble(hex[0]);
|
||||
const auto g = parse_hex_nibble(hex[1]);
|
||||
const auto b = parse_hex_nibble(hex[2]);
|
||||
const auto a = hex.size() == 4U ? parse_hex_nibble(hex[3])
|
||||
: pp::foundation::Result<std::uint8_t>::success(255);
|
||||
if (!r || !g || !b || !a) {
|
||||
return pp::foundation::Result<ColorRgba8>::failure(
|
||||
pp::foundation::Status::invalid_argument("color contains a non-hex character"));
|
||||
}
|
||||
color = ColorRgba8 { .r = r.value(), .g = g.value(), .b = b.value(), .a = a.value() };
|
||||
return pp::foundation::Result<ColorRgba8>::success(color);
|
||||
}
|
||||
|
||||
const auto r = parse_hex_byte(hex.substr(0, 2));
|
||||
const auto g = parse_hex_byte(hex.substr(2, 2));
|
||||
const auto b = parse_hex_byte(hex.substr(4, 2));
|
||||
const auto a = hex.size() == 8U ? parse_hex_byte(hex.substr(6, 2))
|
||||
: pp::foundation::Result<std::uint8_t>::success(255);
|
||||
if (!r || !g || !b || !a) {
|
||||
return pp::foundation::Result<ColorRgba8>::failure(
|
||||
pp::foundation::Status::invalid_argument("color contains a non-hex character"));
|
||||
}
|
||||
|
||||
color = ColorRgba8 { .r = r.value(), .g = g.value(), .b = b.value(), .a = a.value() };
|
||||
return pp::foundation::Result<ColorRgba8>::success(color);
|
||||
}
|
||||
|
||||
}
|
||||
19
src/ui_core/color.h
Normal file
19
src/ui_core/color.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "foundation/result.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
namespace pp::ui {
|
||||
|
||||
struct ColorRgba8 {
|
||||
std::uint8_t r = 0;
|
||||
std::uint8_t g = 0;
|
||||
std::uint8_t b = 0;
|
||||
std::uint8_t a = 255;
|
||||
};
|
||||
|
||||
[[nodiscard]] pp::foundation::Result<ColorRgba8> parse_hex_color(std::string_view value) noexcept;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user