parcel 0.2.2
Wrappable, wire-transferable C++23 value system with JSON serialization
Loading...
Searching...
No Matches
walk.h
Go to the documentation of this file.
1#pragma once
2
18#include <parcel/cell.h>
19#include <parcel/list.h>
20#include <parcel/map.h>
21#include <parcel/struct.h>
22#include <parcel/union.h>
23
24#include <string>
25#include <utility>
26#include <vector>
27
28#if defined(__cpp_lib_generator) && __cpp_lib_generator >= 202207L
29#include <generator>
30#define PARCEL_HAS_GENERATOR 1
31#else
32#define PARCEL_HAS_GENERATOR 0
33#endif
34
35namespace parcel {
36
38struct WalkEntry {
40 std::string path;
43};
44
45namespace detail {
46
47// Escape a path component per RFC 6901: '~' -> "~0", '/' -> "~1". Order
48// matters — '~' must be substituted before '/' so the substituted '/' is
49// not double-escaped on the next pass.
50inline std::string jp_escape(const std::string_view k) {
51 std::string out;
52 out.reserve(k.size());
53 for (const char c : k) {
54 if (c == '~') {
55 out += "~0";
56 } else if (c == '/') {
57 out += "~1";
58 } else {
59 out += c;
60 }
61 }
62 return out;
63}
64
65inline void walk_collect(cell_t const& root, const std::string& path, std::vector<WalkEntry>& out) {
66 if (!root) {
67 return;
68 }
69 out.push_back({path, root});
70
71 if (auto const* list = dynamic_cast<ListCell const*>(root.get()); list != nullptr) {
72 std::size_t i = 0;
73 for (auto const& el : list->value) {
74 std::string sub = path;
75 sub += '/';
76 sub += std::to_string(i);
77 walk_collect(el, sub, out);
78 ++i;
79 }
80 return;
81 }
82
83 if (auto const* map = dynamic_cast<MapCell const*>(root.get()); map != nullptr) {
84 for (auto const& [k, v] : map->value) {
85 std::string sub = path;
86 sub += '/';
87 sub += jp_escape(k);
88 walk_collect(v, sub, out);
89 }
90 return;
91 }
92}
93
94} // namespace detail
95
105[[nodiscard]] inline std::vector<WalkEntry> walk_to_vector(cell_t const& root) {
106 std::vector<WalkEntry> out;
107 detail::walk_collect(root, "", out);
108 return out;
109}
110
111#if PARCEL_HAS_GENERATOR
112namespace detail {
113
114// Recursive coroutine helper for `walk`. Mirrors `walk_collect`'s contract
115// but yields each node lazily as the consumer pulls — no full materialization.
116inline std::generator<WalkEntry> walk_node(cell_t root, std::string path) {
117 if (!root) {
118 co_return;
119 }
120 co_yield WalkEntry{path, root};
121
122 if (auto const* list = dynamic_cast<ListCell const*>(root.get()); list != nullptr) {
123 std::size_t i = 0;
124 for (auto const& el : list->value) {
125 std::string sub = path;
126 sub += '/';
127 sub += std::to_string(i);
128 for (auto&& entry : walk_node(el, std::move(sub))) {
129 co_yield std::move(entry);
130 }
131 ++i;
132 }
133 co_return;
134 }
135
136 if (auto const* map = dynamic_cast<MapCell const*>(root.get()); map != nullptr) {
137 for (auto const& [k, v] : map->value) {
138 std::string sub = path;
139 sub += '/';
140 sub += jp_escape(k);
141 for (auto&& entry : walk_node(v, std::move(sub))) {
142 co_yield std::move(entry);
143 }
144 }
145 co_return;
146 }
147}
148
149} // namespace detail
150
164inline std::generator<WalkEntry> walk(cell_t root) {
165 return detail::walk_node(std::move(root), "");
166}
167#endif
168
169} // namespace parcel
Core ICell interface, cell_t handle, BaseCell CRTP base, and CellLike concept.
std::shared_ptr< ICell > cell_t
Shared handle to any ICell-derived value — the canonical cell pointer.
Definition cell.h:68
TypedListCell<T> and heterogeneous ListCell with their descriptors.
TypedMapCell<T> and heterogeneous MapCell with their descriptors.
StructCell CRTP base, FieldsBuilder, and the per-field descriptors.
One node yielded by a tree walk: (json-pointer-path, cell).
Definition walk.h:38
std::string path
JSON-pointer-style path to the cell ("" for the root).
Definition walk.h:40
cell_t cell
The cell at that path.
Definition walk.h:42
UnionCell<Ts...> closed-set polymorphic cell and its descriptor.
std::vector< WalkEntry > walk_to_vector(cell_t const &root)
Eagerly collect every cell in root's tree, depth-first.
Definition walk.h:105