2023-01-22 07:09:11 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2021, sin-ack <sin-ack@protonmail.com>
|
|
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <AK/Error.h>
|
2023-04-22 18:21:31 +03:00
|
|
|
#include <AK/Format.h>
|
2023-01-22 07:09:11 +03:00
|
|
|
#include <AK/Forward.h>
|
|
|
|
#include <AK/Traits.h>
|
|
|
|
|
|
|
|
namespace AK {
|
|
|
|
|
|
|
|
/// The base, abstract class for stream operations. This class defines the
|
|
|
|
/// operations one can perform on every stream.
|
|
|
|
/// Operations without a sensible default that are unsupported by an implementation
|
|
|
|
/// of a Stream should return EBADF as an error.
|
|
|
|
class Stream {
|
|
|
|
public:
|
|
|
|
/// Reads into a buffer, with the maximum size being the size of the buffer.
|
|
|
|
/// The amount of bytes read can be smaller than the size of the buffer.
|
|
|
|
/// Returns either the bytes that were read, or an errno in the case of
|
|
|
|
/// failure.
|
2023-02-25 00:38:01 +03:00
|
|
|
virtual ErrorOr<Bytes> read_some(Bytes) = 0;
|
2023-01-22 07:09:11 +03:00
|
|
|
/// Tries to fill the entire buffer through reading. Returns whether the
|
|
|
|
/// buffer was filled without an error.
|
2023-03-01 17:27:35 +03:00
|
|
|
virtual ErrorOr<void> read_until_filled(Bytes);
|
2023-01-22 07:09:11 +03:00
|
|
|
/// Reads the stream until EOF, storing the contents into a ByteBuffer which
|
|
|
|
/// is returned once EOF is encountered. The block size determines the size
|
|
|
|
/// of newly allocated chunks while reading.
|
|
|
|
virtual ErrorOr<ByteBuffer> read_until_eof(size_t block_size = 4096);
|
|
|
|
/// Discards the given number of bytes from the stream. As this is usually used
|
2023-03-01 17:27:35 +03:00
|
|
|
/// as an efficient version of `read_until_filled`, it returns an error
|
2023-01-22 07:09:11 +03:00
|
|
|
/// if reading failed or if not all bytes could be discarded.
|
|
|
|
/// Unless specifically overwritten, this just uses read() to read into an
|
|
|
|
/// internal stack-based buffer.
|
|
|
|
virtual ErrorOr<void> discard(size_t discarded_bytes);
|
|
|
|
|
|
|
|
/// Tries to write the entire contents of the buffer. It is possible for
|
|
|
|
/// less than the full buffer to be written. Returns either the amount of
|
|
|
|
/// bytes written into the stream, or an errno in the case of failure.
|
2023-02-25 00:38:01 +03:00
|
|
|
virtual ErrorOr<size_t> write_some(ReadonlyBytes) = 0;
|
2023-01-22 07:09:11 +03:00
|
|
|
/// Same as write, but does not return until either the entire buffer
|
|
|
|
/// contents are written or an error occurs.
|
2023-03-01 17:37:45 +03:00
|
|
|
virtual ErrorOr<void> write_until_depleted(ReadonlyBytes);
|
2023-01-22 07:09:11 +03:00
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
requires(requires(Stream& stream) { { T::read_from_stream(stream) } -> SameAs<ErrorOr<T>>; })
|
|
|
|
ErrorOr<T> read_value()
|
|
|
|
{
|
|
|
|
return T::read_from_stream(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
requires(Traits<T>::is_trivially_serializable())
|
|
|
|
ErrorOr<T> read_value()
|
|
|
|
{
|
|
|
|
alignas(T) u8 buffer[sizeof(T)] = {};
|
2023-03-01 17:27:35 +03:00
|
|
|
TRY(read_until_filled({ &buffer, sizeof(buffer) }));
|
2023-01-22 07:09:11 +03:00
|
|
|
return bit_cast<T>(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
requires(requires(T t, Stream& stream) { { t.write_to_stream(stream) } -> SameAs<ErrorOr<void>>; })
|
|
|
|
ErrorOr<void> write_value(T const& value)
|
|
|
|
{
|
|
|
|
return value.write_to_stream(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
requires(Traits<T>::is_trivially_serializable())
|
|
|
|
ErrorOr<void> write_value(T const& value)
|
|
|
|
{
|
2023-03-01 17:37:45 +03:00
|
|
|
return write_until_depleted({ &value, sizeof(value) });
|
2023-01-22 07:09:11 +03:00
|
|
|
}
|
|
|
|
|
2023-04-22 18:21:31 +03:00
|
|
|
template<typename... Parameters>
|
2023-04-24 22:37:34 +03:00
|
|
|
ErrorOr<void> write_formatted(CheckedFormatString<Parameters...>&& fmtstr, Parameters const&... parameters)
|
2023-04-22 18:21:31 +03:00
|
|
|
{
|
|
|
|
VariadicFormatParams<AllowDebugOnlyFormatters::No, Parameters...> variadic_format_params { parameters... };
|
2023-04-24 22:37:34 +03:00
|
|
|
TRY(write_formatted_impl(fmtstr.view(), variadic_format_params));
|
2023-04-22 18:21:31 +03:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2023-01-22 07:09:11 +03:00
|
|
|
/// Returns whether the stream has reached the end of file. For sockets,
|
|
|
|
/// this most likely means that the protocol has disconnected (in the case
|
|
|
|
/// of TCP). For seekable streams, this means the end of the file. Note that
|
|
|
|
/// is_eof will only return true _after_ a read with 0 length, so this
|
|
|
|
/// method should be called after a read.
|
|
|
|
virtual bool is_eof() const = 0;
|
|
|
|
|
|
|
|
virtual bool is_open() const = 0;
|
|
|
|
virtual void close() = 0;
|
|
|
|
|
|
|
|
virtual ~Stream()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
/// Provides a default implementation of read_until_eof that works for streams
|
|
|
|
/// that behave like POSIX file descriptors. expected_file_size can be
|
|
|
|
/// passed as a heuristic for what the Stream subclass expects the file
|
|
|
|
/// content size to be in order to reduce allocations (does not affect
|
|
|
|
/// actual reading).
|
|
|
|
ErrorOr<ByteBuffer> read_until_eof_impl(size_t block_size, size_t expected_file_size = 0);
|
2023-04-24 22:37:34 +03:00
|
|
|
|
|
|
|
private:
|
|
|
|
ErrorOr<void> write_formatted_impl(StringView, TypeErasedFormatParams&);
|
2023-01-22 07:09:11 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
enum class SeekMode {
|
|
|
|
SetPosition,
|
|
|
|
FromCurrentPosition,
|
|
|
|
FromEndPosition,
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Adds seekability to a Stream. Classes inheriting from SeekableStream
|
|
|
|
/// will be seekable to any point in the stream.
|
|
|
|
class SeekableStream : public Stream {
|
|
|
|
public:
|
|
|
|
/// Seeks to the given position in the given mode. Returns either the
|
|
|
|
/// current position of the file, or an errno in the case of an error.
|
|
|
|
virtual ErrorOr<size_t> seek(i64 offset, SeekMode) = 0;
|
|
|
|
/// Returns the current position of the file, or an errno in the case of
|
|
|
|
/// an error.
|
|
|
|
virtual ErrorOr<size_t> tell() const;
|
|
|
|
/// Returns the total size of the stream, or an errno in the case of an
|
|
|
|
/// error. May not preserve the original position on the stream on failure.
|
|
|
|
virtual ErrorOr<size_t> size();
|
|
|
|
/// Shrinks or extends the stream to the given size. Returns an errno in
|
|
|
|
/// the case of an error.
|
2023-01-29 15:49:42 +03:00
|
|
|
virtual ErrorOr<void> truncate(size_t length) = 0;
|
2023-01-22 07:09:11 +03:00
|
|
|
/// Seeks until after the given amount of bytes to be discarded instead of
|
|
|
|
/// reading and discarding everything manually;
|
|
|
|
virtual ErrorOr<void> discard(size_t discarded_bytes) override;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#if USING_AK_GLOBALLY
|
|
|
|
using AK::SeekMode;
|
|
|
|
#endif
|