Skip to content

Commit 6b5fb4c

Browse files
committed
Add documentation for rfl::AddNamespacedTagsToVariants
1 parent 5c8d6c5 commit 6b5fb4c

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

docs/concepts/processors.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ reflect-cpp currently supports the following processors:
3535

3636
- `rfl::AddStructName`
3737
- `rfl::AddTagsToVariants`
38+
- `rfl::AddNamespacedTagsToVariants`
3839
- `rfl::AllowRawPtrs`
3940
- `rfl::DefaultIfMissing`
4041
- `rfl::NoExtraFields`
@@ -117,6 +118,89 @@ struct key_pressed_t {
117118
Note that there are other ways to address problems like this, for instance `rfl::TaggedUnion`.
118119
Please refer to the relevant sections of the documentation.
119120

121+
### `rfl::AddNamespacedTagsToVariants`
122+
123+
This processor is similar to `rfl::AddTagsToVariants`, but instead of using just the struct name as the tag, it uses the full namespaced type name. This is particularly useful when you have:
124+
125+
1. Structs with the same name in different namespaces
126+
2. Structs with `rfl::Generic` fields that would otherwise create naming conflicts
127+
128+
#### Use-case: Structs with the same name in different namespaces
129+
130+
Consider this example where `rfl::AddTagsToVariants` would fail:
131+
132+
```cpp
133+
namespace Result {
134+
struct Message {
135+
std::string result;
136+
};
137+
}
138+
139+
namespace Error {
140+
struct Message {
141+
std::string error;
142+
int error_id;
143+
};
144+
}
145+
146+
using Messages = std::variant<Result::Message, Error::Message>;
147+
148+
const auto msgs = std::vector<Messages>{
149+
Result::Message{.result = "success"},
150+
Error::Message{.error = "failure", .error_id = 404}
151+
};
152+
153+
// This would cause problems with rfl::AddTagsToVariants because both
154+
// structs have the same name "Message"
155+
156+
// But this works perfectly:
157+
const auto json_string = rfl::json::write<rfl::AddNamespacedTagsToVariants>(msgs);
158+
const auto msgs2 = rfl::json::read<std::vector<Messages>, rfl::AddNamespacedTagsToVariants>(json_string);
159+
```
160+
161+
The resulting JSON includes the full namespace path:
162+
163+
```json
164+
[
165+
{"Result::Message": {"result": "success"}},
166+
{"Error::Message": {"error": "failure", "error_id": 404}}
167+
]
168+
```
169+
170+
#### Use-case: Structs with `rfl::Generic` fields that would otherwise create naming conflicts
171+
172+
Another use case is with `rfl::Generic` fields, where multiple structs contain generic fields that would otherwise create naming conflicts:
173+
174+
```cpp
175+
struct APIResult {
176+
rfl::Generic result; // Could be string, number, object, etc.
177+
};
178+
179+
struct APIError {
180+
rfl::Generic error; // Could be string, number, object, etc.
181+
};
182+
183+
using APIResponse = std::variant<APIResult, APIError>;
184+
185+
const auto response = APIResult{.result = std::string("200")};
186+
187+
// Without namespaces, both Generic fields would have the same tag name.
188+
// With namespaces, they get unique identifiers:
189+
const auto json_string = rfl::json::write<rfl::AddNamespacedTagsToVariants>(response);
190+
```
191+
192+
This generates:
193+
194+
```json
195+
{"APIResult": {"result": {"std::string": "200"}}}
196+
```
197+
198+
#### When to use `rfl::AddNamespacedTagsToVariants` vs `rfl::AddTagsToVariants`
199+
200+
- Use `rfl::AddTagsToVariants` when struct names are unique and you want shorter, cleaner tags
201+
- Use `rfl::AddNamespacedTagsToVariants` when you have naming conflicts or need to distinguish between types in different namespaces
202+
- Custom tags (using `Tag = rfl::Literal<"custom_name">`) work with both processors and are not affected by the namespace handling
203+
120204
### `rfl::AllowRawPtrs`
121205

122206
By default, reflect-cpp does not allow *reading into* raw pointers, `std::string_view` or `std::span`.

docs/variants_and_tagged_unions.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,44 @@ const auto r2 = rfl::json::read<Shapes, rfl::AddTagsToVariants>(json_string);
5757

5858
Please refer to the section on processors in this documentation for more information.
5959

60+
## Automatic tags with full namespaces
61+
62+
In some cases, you might have struct name conflicts between different namespaces, or types that would generate identical tags when namespaces are removed. For these situations, you can use `rfl::AddNamespacedTagsToVariants` instead:
63+
64+
```cpp
65+
namespace Result {
66+
struct Message {
67+
std::string result;
68+
};
69+
}
70+
71+
namespace Error {
72+
struct Message {
73+
std::string error;
74+
int error_id;
75+
};
76+
}
77+
78+
using Messages = std::variant<Result::Message, Error::Message>;
79+
80+
const Messages msg = Error::Message{.error = "Something went wrong", .error_id = 404};
81+
82+
const auto json_string = rfl::json::write<rfl::AddNamespacedTagsToVariants>(msg);
83+
```
84+
85+
This generates JSON with fully qualified type names:
86+
87+
```json
88+
{"Error::Message":{"error":"Something went wrong","error_id":404}}
89+
```
90+
91+
The key differences between `rfl::AddTagsToVariants` and `rfl::AddNamespacedTagsToVariants`:
92+
93+
- `rfl::AddTagsToVariants` uses just the struct name (e.g., `"Message"`)
94+
- `rfl::AddNamespacedTagsToVariants` uses the full namespaced name (e.g., `"Error::Message"`)
95+
- Both respect custom tags defined with `using Tag = rfl::Literal<"custom_name">`
96+
- Use the namespaced version when you are using `rfl::Generic` or need to distinguish between types in different namespaces and don't want to manually tag them as above
97+
6098
## `rfl::TaggedUnion` (internally tagged)
6199

62100
Another way to solve this problem is to add a tag inside the class. That is why we have provided a helper class for these purposes: `rfl::TaggedUnion`.

0 commit comments

Comments
 (0)