Serenity Operating System
1/*
2 * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/ByteBuffer.h>
10#include <AK/Debug.h>
11#include <AK/DeprecatedString.h>
12#include <AK/Format.h>
13#include <AK/ScopeGuard.h>
14#include <LibSQL/Forward.h>
15#include <LibSQL/Heap.h>
16#include <string.h>
17
18namespace SQL {
19
20class Serializer {
21public:
22 Serializer() = default;
23
24 Serializer(RefPtr<Heap> heap)
25 : m_heap(heap)
26 {
27 }
28
29 void get_block(u32 pointer)
30 {
31 VERIFY(m_heap.ptr() != nullptr);
32 auto buffer_or_error = m_heap->read_block(pointer);
33 if (buffer_or_error.is_error())
34 VERIFY_NOT_REACHED();
35 m_buffer = buffer_or_error.value();
36 m_current_offset = 0;
37 }
38
39 void reset()
40 {
41 m_buffer.clear();
42 m_current_offset = 0;
43 }
44
45 void rewind()
46 {
47 m_current_offset = 0;
48 }
49
50 template<typename T, typename... Args>
51 T deserialize_block(u32 pointer, Args&&... args)
52 {
53 get_block(pointer);
54 return deserialize<T>(forward<Args>(args)...);
55 }
56
57 template<typename T>
58 void deserialize_block_to(u32 pointer, T& t)
59 {
60 get_block(pointer);
61 return deserialize_to<T>(t);
62 }
63
64 template<typename T>
65 void deserialize_to(T& t)
66 {
67 if constexpr (IsArithmetic<T>)
68 memcpy(&t, read(sizeof(T)), sizeof(T));
69 else
70 t.deserialize(*this);
71 }
72
73 void deserialize_to(DeprecatedString& text);
74
75 template<typename T, typename... Args>
76 NonnullOwnPtr<T> make_and_deserialize(Args&&... args)
77 {
78 auto ptr = make<T>(forward<Args>(args)...);
79 ptr->deserialize(*this);
80 return ptr;
81 }
82
83 template<typename T, typename... Args>
84 NonnullRefPtr<T> adopt_and_deserialize(Args&&... args)
85 {
86 auto ptr = adopt_ref(*new T(forward<Args>(args)...));
87 ptr->deserialize(*this);
88 return ptr;
89 }
90
91 template<typename T, typename... Args>
92 T deserialize(Args&&... args)
93 {
94 T t(forward<Args>(args)...);
95 deserialize_to(t);
96 return t;
97 }
98
99 template<typename T>
100 void serialize(T const& t)
101 {
102 if constexpr (IsArithmetic<T>)
103 write((u8 const*)(&t), sizeof(T));
104 else
105 t.serialize(*this);
106 }
107
108 void serialize(DeprecatedString const&);
109
110 template<typename T>
111 bool serialize_and_write(T const& t)
112 {
113 VERIFY(m_heap.ptr() != nullptr);
114 reset();
115 serialize<T>(t);
116 m_heap->add_to_wal(t.pointer(), m_buffer);
117 return true;
118 }
119
120 [[nodiscard]] size_t offset() const { return m_current_offset; }
121 u32 new_record_pointer()
122 {
123 VERIFY(m_heap.ptr() != nullptr);
124 return m_heap->new_record_pointer();
125 }
126
127 bool has_block(u32 pointer) const
128 {
129 VERIFY(m_heap.ptr() != nullptr);
130 return pointer < m_heap->size();
131 }
132
133 Heap& heap()
134 {
135 VERIFY(m_heap.ptr() != nullptr);
136 return *(m_heap.ptr());
137 }
138
139private:
140 void write(u8 const* ptr, size_t sz)
141 {
142 if constexpr (SQL_DEBUG)
143 dump(ptr, sz, "(out) =>");
144 m_buffer.append(ptr, sz);
145 m_current_offset += sz;
146 }
147
148 u8 const* read(size_t sz)
149 {
150 auto buffer_ptr = m_buffer.offset_pointer(m_current_offset);
151 if constexpr (SQL_DEBUG)
152 dump(buffer_ptr, sz, "<= (in)");
153 m_current_offset += sz;
154 return buffer_ptr;
155 }
156
157 static void dump(u8 const* ptr, size_t sz, DeprecatedString const& prefix)
158 {
159 StringBuilder builder;
160 builder.appendff("{0} {1:04x} | ", prefix, sz);
161 Vector<DeprecatedString> bytes;
162 for (auto ix = 0u; ix < sz; ++ix) {
163 bytes.append(DeprecatedString::formatted("{0:02x}", *(ptr + ix)));
164 }
165 StringBuilder bytes_builder;
166 bytes_builder.join(' ', bytes);
167 builder.append(bytes_builder.to_deprecated_string());
168 dbgln(builder.to_deprecated_string());
169 }
170
171 ByteBuffer m_buffer {};
172 size_t m_current_offset { 0 };
173 RefPtr<Heap> m_heap { nullptr };
174};
175
176}