Haio 0.2.X
Homebrew Asset IO/CDN
Loading...
Searching...
No Matches
haio_pipe.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "haio_registry.hpp"
4
5#include <fstream>
6#include <iterator>
7#include <utility>
8
9/**
10 * lazily composed conversions, checked when the chain is built rather than when it
11 * runs. a stage is a callable returning Result<T>, and chaining two short circuits:
12 * the second never runs if the first failed, and the error rides through untouched.
13 *
14 * const auto pipeline = Decode | Convert<Color::ETC1> | Encode<Format::KTX2>;
15 * const auto result = pipeline(bytes);
16 *
17 * the names repeat those in Haio::Codecs on purpose: a stage is a value that
18 * composes, not a function that runs, so Pipe::Encode<Format::KTX2> is a thing you
19 * hold and Codecs::Encode<Format::KTX2, Color::ETC1> is a thing you call.
20 */
21namespace Haio::Pipe {
22
23template <typename Fn>
24struct Stage {
25 Fn fn;
26
27 constexpr auto operator()(auto&& in) const {
28 return fn(std::forward<decltype(in)>(in));
29 }
30};
31
32template <typename A, typename B>
33constexpr auto operator|(Stage<A> first, Stage<B> second) {
34 return Stage{[first, second](auto&& in) {
35 auto middle = first(std::forward<decltype(in)>(in));
36 using Out = decltype(second(*std::move(middle)));
37 if (!middle) return Out{std::unexpected(middle.error())};
38 return second(*std::move(middle));
39 }};
40}
41
42namespace Detail {
43
44inline Blob asBlob(const Blob& in) { return in; }
45
46/** anything byte shaped enters the pipeline as a file of undecided format */
47inline Blob asBlob(const auto& bytes) {
48 return Blob{Format::RAW, Color::RGBA8888, {}, {}, {bytes.begin(), bytes.end()}};
49}
50
51}
52
53/**
54 * the bytes say what they are, nobody has to know beforehand.
55 *
56 * @todo the output is pinned to rgba8888 because a pipeline is typed and the input
57 * is not. a jpeg is natively yuv, so asking for y4m through here would go through
58 * rgb for nothing; Codecs::Decode<Format::JPEG, Color::YUV420> is the way around it.
59 */
60inline constexpr auto Decode = Stage{[](const auto& in) -> Result<Image<Color::RGBA8888>> {
61 return Haio::Decode(Detail::asBlob(in));
62}};
63
64/** the target colour is named, the source is deduced from whatever arrives */
65template <Color To>
66inline constexpr auto Convert = Stage{[]<Color From>(Image<From> src) -> Result<Image<To>>
68 return Codecs::Convert<From, To>(std::move(src));
69}};
70
71/** the container is named, the colour comes from the image in hand */
72template <Format F>
73inline constexpr auto Encode = Stage{[]<Color P>(Image<P> src) -> Result<Blob>
75 return Codecs::Encode<F, P>(std::move(src));
76}};
77
78/** the result type follows whatever the chain ends in, image or blob */
79template <typename Fn>
80auto operator>>(std::istream& in, const Stage<Fn>& stage) {
81 using Out = decltype(stage(std::declval<const std::vector<uint8_t>&>()));
82
83 if (!in) return Out{std::unexpected(Error{ErrorCode::Io, "could not read input"})};
84
85 // a directory opens as a stream without complaint and only fails on the first
86 // read, so the read itself has to be guarded and not just the open
87 std::vector<uint8_t> data;
88 try {
89 data.assign(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>());
90 } catch (const std::exception&) {
91 return Out{std::unexpected(Error{ErrorCode::Io, "could not read input"})};
92 }
93 if (in.bad()) return Out{std::unexpected(Error{ErrorCode::Io, "failed while reading input"})};
94
95 return stage(data);
96}
97
98}
99
100namespace Haio {
101
102/** the sugar: input >> pipeline >> output, with the Result surviving the chain */
103inline Result<void> operator>>(const Result<Blob>& result, std::ostream& out) {
104 if (!result) return std::unexpected(result.error());
105
106 out.write(reinterpret_cast<const char*>(result->data.data()),
107 static_cast<std::streamsize>(result->data.size()));
108 if (!out) return std::unexpected(Error{ErrorCode::Io, "could not write output"});
109 return {};
110}
111
112}
Result< Image< To > > Convert(Image< From >)=delete
Result< Blob > Encode(Image< P >)=delete
Blob asBlob(const Blob &in)
Definition haio_pipe.hpp:44
constexpr auto operator|(Stage< A > first, Stage< B > second)
Definition haio_pipe.hpp:33
auto operator>>(std::istream &in, const Stage< Fn > &stage)
Definition haio_pipe.hpp:80
constexpr auto Decode
Definition haio_pipe.hpp:60
constexpr auto Encode
Definition haio_pipe.hpp:73
constexpr auto Convert
Definition haio_pipe.hpp:66
Definition haio.hpp:11
Result< void > operator>>(const Result< Blob > &result, std::ostream &out)
std::expected< T, Error > Result
constexpr auto operator()(auto &&in) const
Definition haio_pipe.hpp:27