|
| 1 | +# BSON |
| 2 | + |
| 3 | +For BSON support, you must also include the header `<rfl/bson.hpp>` and link to the libbson library (https://github.com/mongodb/libbson). |
| 4 | + |
| 5 | +Like the name implies, BSON is a JSON-like binary format. It is most notably used by MongoDB. |
| 6 | + |
| 7 | +## Reading and writing |
| 8 | + |
| 9 | +Suppose you have a struct like this: |
| 10 | + |
| 11 | +```cpp |
| 12 | +struct Person { |
| 13 | + std::string first_name; |
| 14 | + std::string last_name; |
| 15 | + rfl::Timestamp<"%Y-%m-%d"> birthday; |
| 16 | + std::vector<Person> children; |
| 17 | +}; |
| 18 | +``` |
| 19 | +
|
| 20 | +A `person` can be turned into a bytes vector like this: |
| 21 | +
|
| 22 | +```cpp |
| 23 | +const auto person = Person{...}; |
| 24 | +const auto bytes = rfl::bson::write(person); |
| 25 | +``` |
| 26 | + |
| 27 | +You can parse bytes like this: |
| 28 | + |
| 29 | +```cpp |
| 30 | +const rfl::Result<Person> result = rfl::bson::read<Person>(bytes); |
| 31 | +``` |
| 32 | + |
| 33 | +## Loading and saving |
| 34 | + |
| 35 | +You can also load and save to disc using a very similar syntax: |
| 36 | + |
| 37 | +```cpp |
| 38 | +const rfl::Result<Person> result = rfl::bson::load<Person>("/path/to/file.bson"); |
| 39 | + |
| 40 | +const auto person = Person{...}; |
| 41 | +rfl::bson::save("/path/to/file.bson", person); |
| 42 | +``` |
| 43 | +
|
| 44 | +## Reading from and writing into streams |
| 45 | +
|
| 46 | +You can also read from and write into any `std::istream` and `std::ostream` respectively. |
| 47 | +
|
| 48 | +```cpp |
| 49 | +const rfl::Result<Person> result = rfl::bson::read<Person>(my_istream); |
| 50 | +
|
| 51 | +const auto person = Person{...}; |
| 52 | +rfl::bson::write(person, my_ostream); |
| 53 | +``` |
| 54 | + |
| 55 | +Note that `std::cout` is also an ostream, so this works as well: |
| 56 | + |
| 57 | +```cpp |
| 58 | +rfl::bson::write(person, std::cout) << std::endl; |
| 59 | +``` |
| 60 | +
|
| 61 | +(Since BSON is a binary format, the readability of this will be limited, but it might be useful for debugging). |
| 62 | +
|
| 63 | +## Custom constructors |
| 64 | +
|
| 65 | +One of the great things about C++ is that it gives you control over |
| 66 | +when and how you code is compiled. |
| 67 | +
|
| 68 | +For large and complex systems of structs, it is often a good idea to split up |
| 69 | +your code into smaller compilation units. You can do so using custom constructors. |
| 70 | +
|
| 71 | +For the BSON format, these must be a static function on your struct or class called |
| 72 | +`from_bson` that take a `rfl::bson::Reader::InputVarType` as input and return |
| 73 | +the class or the class wrapped in `rfl::Result`. |
| 74 | +
|
| 75 | +In your header file you can write something like this: |
| 76 | +
|
| 77 | +```cpp |
| 78 | +struct Person { |
| 79 | + rfl::Rename<"firstName", std::string> first_name; |
| 80 | + rfl::Rename<"lastName", std::string> last_name; |
| 81 | + rfl::Timestamp<"%Y-%m-%d"> birthday; |
| 82 | +
|
| 83 | + using InputVarType = typename rfl::bson::Reader::InputVarType; |
| 84 | + static rfl::Result<Person> from_bson(const InputVarType& _obj); |
| 85 | +}; |
| 86 | +``` |
| 87 | + |
| 88 | +And in your source file, you implement `from_bson` as follows: |
| 89 | + |
| 90 | +```cpp |
| 91 | +rfl::Result<Person> Person::from_bson(const InputVarType& _obj) { |
| 92 | + const auto from_nt = [](auto&& _nt) { |
| 93 | + return rfl::from_named_tuple<Person>(std::move(_nt)); |
| 94 | + }; |
| 95 | + return rfl::bson::read<rfl::named_tuple_t<Person>>(_obj) |
| 96 | + .transform(from_nt); |
| 97 | +} |
| 98 | +``` |
| 99 | +
|
| 100 | +This will force the compiler to only compile the BSON parsing when the source file is compiled. |
0 commit comments