aboutsummaryrefslogtreecommitdiff
path: root/include/cru/base/io/Stream.h
blob: e0b6162705f124f690c31169d852f8ac4265f508 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#pragma once

#include "../Base.h"

#include "../Exception.h"
#include "../String.h"

#include <cstddef>

namespace cru::io {
class CRU_BASE_API StreamOperationNotSupportedException : public Exception {
 public:
  explicit StreamOperationNotSupportedException(String operation);

  CRU_DEFAULT_DESTRUCTOR(StreamOperationNotSupportedException)

 public:
  String GetOperation() const { return operation_; }

 public:
  static void CheckSeek(bool seekable);
  static void CheckRead(bool readable);
  static void CheckWrite(bool writable);

 private:
  String operation_;
};

class CRU_BASE_API StreamAlreadyClosedException : public Exception {
 public:
  StreamAlreadyClosedException();

  CRU_DEFAULT_DESTRUCTOR(StreamAlreadyClosedException)

  static void Check(bool closed);
};

#define CRU_STREAM_IMPLEMENT_CLOSE_BY_DO_CLOSE \
  void Close() override { DoClose(); }

#define CRU_STREAM_BEGIN_CLOSE \
  if (GetClosed()) return;     \
  CloseGuard close_guard(this);

/**
 * All stream is thread-unsafe by default unless being documented.
 */
class CRU_BASE_API Stream : public Object {
 protected:
  struct SupportedOperations {
    std::optional<bool> can_seek;
    std::optional<bool> can_read;
    std::optional<bool> can_write;
  };

  struct CloseGuard {
    explicit CloseGuard(Stream* stream) : stream(stream) {}
    ~CloseGuard() { stream->SetClosed(true); }
    Stream* stream;
  };

 protected:
  explicit Stream(SupportedOperations supported_operations = {});
  Stream(std::optional<bool> can_seek, std::optional<bool> can_read,
         std::optional<bool> can_write);

 public:
  enum class SeekOrigin { Current, Begin, End };

  CRU_DELETE_COPY(Stream)
  CRU_DELETE_MOVE(Stream)

  ~Stream() override = default;

 public:
  bool CanSeek();
  Index Seek(Index offset, SeekOrigin origin = SeekOrigin::Current);
  Index Tell();
  void Rewind();
  Index GetSize();

  bool CanRead();
  Index Read(std::byte* buffer, Index offset, Index size);
  Index Read(std::byte* buffer, Index size);
  Index Read(char* buffer, Index offset, Index size);
  Index Read(char* buffer, Index size);

  bool CanWrite();
  Index Write(const std::byte* buffer, Index offset, Index size);
  Index Write(const std::byte* buffer, Index size);
  Index Write(const char* buffer, Index offset, Index size);
  Index Write(const char* buffer, Index size);

  void Flush();
  virtual void Close() = 0;

  virtual Buffer ReadToEnd(Index grow_size = 256);

  // Utf8 encoding.
  String ReadToEndAsUtf8String();

 protected:
  virtual bool DoCanSeek();
  virtual bool DoCanRead();
  virtual bool DoCanWrite();
  virtual Index DoSeek(Index offset, SeekOrigin origin);
  virtual Index DoTell();
  virtual void DoRewind();
  virtual Index DoGetSize();
  virtual Index DoRead(std::byte* buffer, Index offset, Index size);
  virtual Index DoWrite(const std::byte* buffer, Index offset, Index size);
  virtual void DoFlush();

  void SetSupportedOperations(SupportedOperations supported_operations) {
    supported_operations_ = std::move(supported_operations);
  }

  bool GetClosed() { return closed_; }
  void SetClosed(bool closed) { closed_ = closed; }
  void CheckClosed() { StreamAlreadyClosedException::Check(closed_); }

 private:
  std::optional<SupportedOperations> supported_operations_;
  bool closed_;
};
}  // namespace cru::io