From ede88ae2da1860b4934c56f16b807a1b0d132f7d Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Sun, 24 Dec 2023 23:22:03 -0500 Subject: [PATCH] Add docs and examples for conversions Move the cast conversion comparison table up to the construct namespace docs. Add examples to the into function. --- sus/construct/cast.h | 30 ++++++++---------------- sus/construct/construct.h | 43 +++++++++++++++++++++++++++------- sus/construct/into.h | 25 +++++++++++++++++++- sus/construct/into_unittest.cc | 15 ++++++++++++ 4 files changed, 83 insertions(+), 30 deletions(-) diff --git a/sus/construct/cast.h b/sus/construct/cast.h index c3d9a00dd..ad39b4562 100644 --- a/sus/construct/cast.h +++ b/sus/construct/cast.h @@ -127,39 +127,29 @@ concept Cast = requires(const From& from) { }; /// An infallible conversion (cast) that may lose the original -/// value in the process. If the input can not be represented in the output, +/// value in the process. +/// +/// See the [namespace level documentation]($sus::option) for more about +/// converting types. +/// +/// If the input can not be represented in the output, /// some other value will be produced, which may lead to application bugs and /// memory unsafety if used incorrectly. This behaves like `static_cast()` -/// but without Undefined Behaviour. +/// but does not cause Undefined Behaviour for any input +/// and output type. without Undefined Behaviour. /// /// The [`cast`]($sus::construct::cast) operation is supported for types /// `To` and `From` that satisfy [`Cast`]( /// $sus::construct::Cast). /// -/// Usually prefer to convert between types with the value-preserving methods -/// of [`From`]($sus::construct::From) and -/// [`Into`]($sus::construct::Into) and [`TryInto`]($sus::construct::TryInto) -/// when possible. [`Cast`]($sus::construct::Cast) is required for converting -/// from floating point to integer values, and from larger integer types to -/// floating point, as these are lossy conversions. -/// -/// | Concept | Usage | Infallible | Preserves values | -/// | ------- | ----- | ---------- | ---------------- | -/// | [`From`]($sus::construct::From) / [`Into`]($sus::construct::Into) | `T::from(x)` / [`sus::into(x)`]($sus::construct::into) | ✅ | ✅ | -/// | [`TryFrom`]($sus::construct::TryFrom) / [`TryInto`]($sus::construct::TryInto) | `T::try_from(x)` / [`sus::try_into(x)`]($sus::construct::try_into) | ❌ | ✅ | -/// | [`Cast`]($sus::construct::Cast) | `sus::cast(x)` | ✅ | ❌ | -/// -/// See [`Cast`]($sus::construct::Cast) for how numeric and -/// primitive values are converted. -/// /// It is best practice to place a `// SAFETY:` comment on use of [`sus::cast`]( /// $sus::construct::cast) in order to explain why the code intends to change /// the value during the cast. /// /// # Examples /// -/// This converts `-1_i64` into a `u32`, which both changes its meaning, -/// becoming a large positive number, and truncates the high 32 bits, losing the +/// This converts `-1` as an `i64` into a `u32`, which both changes its meaning, +/// becoming a large positive number, and truncates the high 32 bits losing the /// original bits. /// ```cpp /// // SAFETY: We're intending to convert negative numbers into large positive diff --git a/sus/construct/construct.h b/sus/construct/construct.h index ce384c463..5aa7e34c3 100644 --- a/sus/construct/construct.h +++ b/sus/construct/construct.h @@ -18,20 +18,45 @@ namespace sus { /// Concepts and functions for constructing and converting between types. /// -/// The [`cast`]($sus::construct::cast) function is built on the -/// [`Cast`]($sus::construct::Cast) concept to convert between numeric and -/// primitive types in a safer way than `static_cast`. +/// # Type conversions /// -/// The [`From`]($sus::construct::From) and [`Into`]($sus::construct::Into) -/// concepts allow converting in a lossless and infallible way between types, -/// and accepting generics that can convert to a desired type. The -/// [`into`]($sus::construct::into) function allows explicit conversion while -/// deducing the target type, such as for converting function arguments or -/// return values. +/// This namespace provides tools for three general methods of converting +/// between types: +/// * Infallible conversions which preserve values: +/// [`From`]($sus::construct::From) / [`Into`]($sus::construct::Into) +/// * Fallible conversions which preserve values or fail explicitly: +/// [`TryFrom`]($sus::construct::TryFrom) / +/// [`TryInto`]($sus::construct::TryInto) +/// * Infallib;e conversions which can change values or lose data: +/// [`Cast`]($sus::construct::Cast) +/// +/// Usually prefer to convert between types with the value-preserving methods +/// of [`From`]($sus::construct::From) and +/// [`Into`]($sus::construct::Into) and [`TryInto`]($sus::construct::TryInto) +/// when possible. [`Cast`]($sus::construct::Cast) is required for converting +/// from floating point to integer values, and from larger integer types to +/// floating point, as these are lossy conversions. +/// +/// The [`into`]($sus::construct::into) function allows explicit conversion +/// while deducing the target type, such as for converting function arguments +/// or return values. +/// +/// | Concept | Usage | Infallible | Preserves values | +/// | ------- | ----- | ---------- | ---------------- | +/// | [`From`]($sus::construct::From) / [`Into`]($sus::construct::Into) | `T::from(x)` / [`sus::into(x)`]($sus::construct::into) | ✅ | ✅ | +/// | [`TryFrom`]($sus::construct::TryFrom) / [`TryInto`]($sus::construct::TryInto) | `T::try_from(x)` / [`sus::try_into(x)`]($sus::construct::try_into) | ❌ | ✅ | +/// | [`Cast`]($sus::construct::Cast) | [`sus::cast(x)`]($sus::construct::cast) | ✅ | ❌ | +/// +/// See [`Cast`]($sus::construct::Cast) for how numeric and +/// primitive values are converted with [`cast`]($sus::construct::cast). +/// +/// # Default construction /// /// The [`Default`]($sus::construct::Default) concept matches types which can be /// default constructed, allowing their use in generic code. /// +/// # Constructing from and holding references +/// /// The [`SafelyConstructibleFromReference`]( /// $sus::construct::SafelyConstructibleFromReference) concept pairs with the /// `[[clang::lifetimebound]]` attribute, which gives better protection with diff --git a/sus/construct/into.h b/sus/construct/into.h index 008f045eb..ab2b57999 100644 --- a/sus/construct/into.h +++ b/sus/construct/into.h @@ -108,6 +108,29 @@ concept Into = /// If the argument to `into` is [`Copy`]($sus::mem::Copy) then it will be /// copied if it is an lvalue or const. If the argument to `into` is an rvalue, /// it will be moved when constructing the `ToType`. +/// +/// # Examples +/// The `into` function deduces the target type while performing an *explicit* +/// conversion via the [`From`]($sus::construct::From) concept (and thus a +/// static `from` method on the target type). +/// ``` +/// auto f = [](Option i) { return i.unwrap_or(-1); }; +/// auto num = 3_i32; +/// // Option can be converted into from its inner type T. +/// sus_check(f(sus::into(num)) == 3); +/// ``` +/// +/// The [`Into`]($sus::construct::Into) concept allows generic code to accept +/// any input type that can be explicitly converted into the target type. The +/// body of the function can use the [`into`]($sus::construct::into) function to +/// perform the conversion. +/// ``` +/// // f() accepts anything that can be converted to Option via into(). +/// auto f = [](Into> auto in) { return Option(sus::into(in)); }; +/// auto num = 3_i32; +/// // num will be passed to Option::from() inside f(). +/// sus_check(f(num).unwrap_or(-1) == 3); +/// ``` template constexpr inline auto into(FromType&& from sus_lifetimebound) noexcept { return __private::IntoRef(::sus::forward(from)); @@ -156,7 +179,7 @@ concept TryInto = ::sus::construct::TryFrom || /// [`Result`]($sus::result::Result). That [`Result`]($sus::result::Result) /// will be the return type of this function. /// -/// # Example +/// # Examples /// ``` /// auto valid = sus::try_into(123_i32).unwrap_or_default(); /// sus_check(valid == 123); diff --git a/sus/construct/into_unittest.cc b/sus/construct/into_unittest.cc index 1cc475832..3b3314b9d 100644 --- a/sus/construct/into_unittest.cc +++ b/sus/construct/into_unittest.cc @@ -150,4 +150,19 @@ TEST(Into, Ref) { EXPECT_EQ(&c.as_value(), &s); } +TEST(Into, Into_Example) { + auto f = [](Option i) { return i.unwrap_or(-1); }; + auto num = 3_i32; + // Option can be converted into from its inner type T. + sus_check(f(sus::into(num)) == 3); +} + +TEST(Into, IntoConcept_Example) { + // f() accepts anything that can be converted to Option via into(). + auto f = [](Into> auto in) { return Option(sus::into(in)); }; + auto num = 3_i32; + // num will be passed to Option::from() inside f(). + sus_check(f(num).unwrap_or(-1) == 3); +} + } // namespace