1
0

refactor: add document for some namespaces

This commit is contained in:
2025-06-25 10:40:05 +08:00
parent adc99274f4
commit a6382d6a22
5 changed files with 149 additions and 88 deletions

View File

@@ -5,34 +5,56 @@
#include <expected>
#endif
/// @brief The reproduction of Rust Option type.
/// @details
/// After writing a program in Rust, I deeply realized the advantages of Rust and its indispensable infrastructure, \c Result.
/// Therefore, it is essential to introduce Result into C++ to strengthen the security of the code.
/// I simulated Result in C++ as best I could, and its members Ok and Err (which are actually done by DeepSeek).
///
/// Why not write it the C++ way? Because the way C++ uses Result is too ugly and not explicit enough.
/// In the way C++ is written, the expected value is gotten by returning directly,
/// and if you encounter void specialization, you must write a pair of curly braces, which is very unclear.
/// For unexpected value, you need to manually build it by calling \c std::unexpected, which is more of a pain.
/// If you need to construct an unexpected value in place, you even need to put a \c std::in_place as the first argument to the constructor,
/// Otherwise, the std::unexpected constructor will not forward the given arguments to the underlying constructor.
///
///
/// @remarks
/// This namespace only work with environment supporting `std::expected` (i.e. C++ 23).
/**
* @brief The reproduction of Rust Option type.
* @details
* After writing programs in Rust, I deeply recognized the advantages of Rust and its indispensable infrastructure Result.
* Therefore, introducing Result into C++ to enhance coding safety is essential.
* I've done my best to simulate Rust's \c Result and its members \c Ok and \c Err (actually, I had DeepSeek simulate them).
*
* Why not write it in C++ style? Because C++'s way of using \c Result is too ugly and not explicit enough.
* In C++'s approach, the expected value is returned directly,
* and when encountering void specialization, you must write a pair of curly braces, which is very unclear.
* For unexpected values, you need to manually construct \c std::unexpected, which is even more painful.
* If you need in-place construction of unexpected values, you even need to put \c std::in_place as the first parameter of the constructor,
* otherwise \c std::unexpected 's constructor won't forward the subsequent parameters to the unexpected value's constructor.
*
* In the \c Result type, type \c E can be any value according to your needs.
* In Rust, an unexpected value type \c Ea can be converted to another unexpected value type \c Eb.
* This feature is implemented through the \c From trait, allowing you to safely wrap one type of unexpected value into another in a function.
* But in C++, we have C++ ways to do the same thing.
* Assuming for each type \c E, we define a separate struct to describe them,
* then we just need to add some extra constructors to the struct to convert them from one type to another.
*
* For example, type \c Ea is a struct named \c IoError.
* In this struct, there is a member of type \c IoErrorKind indicating the category of this IO error.
* At the same time, it has a constructor with its own type as the only parameter, used to construct (copy or move) itself.
* Now in a function, we want to convert it to another type \c Eb named \c SystemError .
* All you need to do is create a new struct named \c SystemError, then write all necessary constructors and other functions for it.
* Then, the key point is to add a constructor with parameter type <TT>const IoError&</TT>.
* This way, we can simply convert type \c Ea to type \c Eb through calls like: <TT>Err<Result<T, E>>(result.error());</TT>.
*
* In Rust, if you want to get human-readable descriptions of unexpected values, you must implement the \c Display trait.
* But you don't need to do this in C++, you must write your own conversion functions to adapt to various output requirements.
* For example, when using \c std::format, you need to write suitable formatting adapters for \c std::format.
* Similarly, when using \c std::cerr 's \c operator<< overload, you also need to write suitable adapters.
* @remarks This namespace only work with environment supporting `std::expected` (i.e. C++ 23).
*/
namespace yycc::rust::result {
#if defined(YYCC_CPPFEAT_EXPECTED)
/**
* @brief Equivalent Rust \c Result in C++
* @tparam T The type of the expected value.
* @tparam E The type of the unexpected value.
*/
template<typename T, typename E>
using Result = std::expected<T, E>;
/**
* @brief Equvialent Rust \c Result::Ok in C++
* @brief Equvialent Rust \c Result::Ok in C++.
* @tparam ResultType The type of the Result instance.
* @param[in] args The arguments for building expected value.
* @return An built Result instance with expected value.
*/
@@ -48,7 +70,8 @@ namespace yycc::rust::result {
}
/**
* @brief Equvialent Rust \c Result::Err in C++
* @brief Equvialent Rust \c Result::Err in C++.
* @tparam ResultType The type of the Result instance.
* @param[in] args The arguments for building unexpected value.
* @return An built Result instance with unexpected value.
*/
@@ -57,30 +80,6 @@ namespace yycc::rust::result {
return ResultType(std::unexpect, std::forward<Args>(args)...);
}
// TODO: Move these comments into Doxygen comments of this namespace.
// YYC MARK:
// Result类型中类型E可以是根据你需求的任意值。
// 在Rust中一个非期望值类型Ea可以被转换为另一个非期望值类型Eb。
// 这一特性通过From trait来实现。这样你就可以在一个函数中安全地将一种非期望值包装成另一种非期望值。
// 但在C++中我们有C++的方式来做同样的事。
// 假设对于每一个类型E我们都分别定义一个struct来描述它们
// 那么我们只需要为struct添加一些额外的构造函数就可以将它们从一个类型转换到另一个。
// ---
// 例如类型Ea是一个名为IoError的struct。
// 在这个struct中有一个类型为IoErrorKind的成员指示了该IO错误的类别。
// 与此同时,它还有一个以自己类型为唯一参数的构造函数,用于构建(复制或移动)它自己。
// 现在在一个函数中。我们希望将它转换为另一个名为SystemError的类型Eb。
// 你需要做的仅仅是新建一个名为SystemError的struct然后为它编写所有必要的构造函数和其它函数。
// 然后,重点是,为它添加一个形参类型为`const IoError&`的构造函数。
// 这样一来,我们就可以通过类似这样的调用:`Err<Result<T, E>>(result.error());`简单地将类型Ea转换为类型Eb。
// YYC MARK:
// 在Rust中如果你想获得非预期值的人类可读说明你就必须要实现名为Display的trait。
// 而你不需要在C++中这样做,你必须编写自己的转换函数,以适应各种输出需求。
// 例如在使用std::format时你需要编写适合std::format的格式化适配器。
// 又如你在使用std::cerr的operator<<重载时,你也需要编写合适的适配器。
#endif
}