diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 2cfdbda..27443e1 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -27,6 +27,15 @@ jobs: cd "${{github.workspace}}/const_format/" cargo test --features "testing" + - uses: actions/checkout@v2 + - name: ci-stable + # apparently github hadn't updated stable by 2021-03-27? + if: ${{ matrix.rust == 'beta' }} + run: | + cargo update + cd "${{github.workspace}}/const_format/" + cargo test --features "testing const_generics" + - uses: actions/checkout@v2 - name: ci-nighly diff --git a/Changelog.md b/Changelog.md index b46f0fd..81008a7 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,15 @@ This is the changelog,summarising changes in each version(some minor changes may # 0.2 +### 0.2.14 + +Fixed a few documentation issues. + +Made the `const_format::fmt` API that uses const generics unconditional, since const generics were stabilized in late 2020 and the `fmt` API requires the nightly compiler. + +Repurposed the "const_generics" feature to generate less code in the `concatcp` and `formatcp` macros, +by moving some of their implementation to a function that uses const generics. + ### 0.2.13 Fixed the assertion macros not to use `std::panic`, using `core::panic` instead, since `core::panic` changed to allow passing a non-literal `&'static str` argument. diff --git a/README.md b/README.md index b507ee2..ec02e6e 100644 --- a/README.md +++ b/README.md @@ -269,14 +269,9 @@ An optimization that requires a few additional nightly features, allowing the `as_bytes_alt` methods and `slice_up_to_len_alt` methods to run in constant time, rather than linear time proportional to the truncated part of the slice. -- "const_generics": -Enables impls that use const generics, currently only used for ergonomics. -Use this when const generics are usable in stable Rust. - -- "nightly_const_generics": -Enables impls that use const generics, currently only used for ergonomics. -This requires a nightly Rust compiler. - +- "const_generics": Requires Rust 1.51.0. +Uses const generics in the implementation of the [`concatcp`] and [`formatcp`] +macros to output less code. # No-std support diff --git a/const_format/Cargo.toml b/const_format/Cargo.toml index f177222..f2b43ba 100644 --- a/const_format/Cargo.toml +++ b/const_format/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "const_format" -version = "0.2.13" +version = "0.2.14" authors = ["rodrimati1992 "] edition = "2018" license = "Zlib" @@ -24,7 +24,7 @@ travis-ci = { repository = "rodrimati1992/const_format_crates/" } default = [] const_generics = [] nightly_const_generics = ["const_generics"] -fmt = [] +fmt = ["const_generics"] derive = ["fmt", "const_format_proc_macros/derive"] assert = ["fmt"] constant_time_as_str = ["fmt"] @@ -37,7 +37,7 @@ docsrs = [] all = ["fmt", "derive", "constant_time_as_str", "nightly_const_generics", "assert", "docsrs"] [dependencies.const_format_proc_macros] -version = "=0.2.8" +version = "=0.2.14" path = "../const_format_proc_macros" [dev-dependencies] diff --git a/const_format/src/const_debug_derive.rs b/const_format/src/const_debug_derive.rs index ea6883b..2501233 100644 --- a/const_format/src/const_debug_derive.rs +++ b/const_format/src/const_debug_derive.rs @@ -51,16 +51,6 @@ /// When this attribute is used it disables the default implementation /// that uses the type parameters generically. /// -/// ### `#[cdeb(crate = "foo::bar")]` -/// -/// The path to the `const_format` crate, useful if you want to reexport the ConstDebug macro, -/// or rename the const_format crate in the Cargo.toml . -/// -/// Example of renaming the `const_format` crate in the Cargo.toml file: -/// ```toml -/// cfmt = {version = "0.*", package = "const_format"} -/// ``` -/// /// Example: /// /// ```rust @@ -77,11 +67,21 @@ /// In this example, there's exactly three impls of /// the `const_debug_fmt` method and [`FormatMarker`] trait. /// +/// ### `#[cdeb(crate = "foo::bar")]` +/// +/// The path to the `const_format` crate, useful if you want to reexport the ConstDebug macro, +/// or rename the `const_format` crate in the Cargo.toml . +/// +/// Example of renaming the `const_format` crate in the Cargo.toml file: +/// ```toml +/// cfmt = {version = "0.*", package = "const_format"} +/// ``` +/// /// # Field attributes /// /// ### `#[cdeb(ignore)]` /// -/// Ignoes the field, pretending that it doesn't exist. +/// Ignores the field, pretending that it doesn't exist. /// /// ### `#[cdeb(with = "module::function")]` /// @@ -195,7 +195,7 @@ /// /// This example demonstrates the `#[cdeb(impls)]` attribute, /// a workaround for deriving this trait for generic types, -/// specifying a list of impls of types that uncnoditionally implement debug formatting +/// specifying a list of impls of types that unconditionally implement debug formatting /// /// ```rust /// #![feature(const_mut_refs)] diff --git a/const_format/src/const_generic_concatcp.rs b/const_format/src/const_generic_concatcp.rs new file mode 100644 index 0000000..a917693 --- /dev/null +++ b/const_format/src/const_generic_concatcp.rs @@ -0,0 +1,22 @@ +//! Reimplements some stuff from concatcp to be const generic instead of macro generated + +use crate::pmr::{LenAndArray, PArgument, PVariant}; + +#[doc(hidden)] +pub const fn __priv_concatenate(input: &[PArgument]) -> LenAndArray<[u8; LEN]> { + let mut out = LenAndArray { + len: 0, + array: [0u8; LEN], + }; + + crate::__for_range! { outer_i in 0..input.len() => + let current = &input[outer_i]; + + match current.elem { + PVariant::Str(s) => crate::__write_pvariant!(str, current, s => out), + PVariant::Int(int) => crate::__write_pvariant!(int, current, int => out), + } + } + + out +} diff --git a/const_format/src/fmt.rs b/const_format/src/fmt.rs index 7d72bc1..0f1de71 100644 --- a/const_format/src/fmt.rs +++ b/const_format/src/fmt.rs @@ -53,7 +53,7 @@ //! - Named, from constant (eg: `formatc!("{FOO}")`): //! Uses the `FOO` constant from the enclosing scope. //! -//! - Named, from locals (eg: `formatc!("{foo}")`): +//! - Named, from locals (eg: `writec!(writable, "{foo}")`): //! Uses the `foo` local variable from the enclosing scope, //! only usable with the [`writec`] macro. //! @@ -187,7 +187,7 @@ //! impl[U,] Foo; //! impl[U,] Foo<&str, U>; //! -//! pub const fn const_debug_fmt(&mut self, f: &mut Formatter<'_>) -> Result<(), Error> { +//! pub const fn const_debug_fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { //! let mut f = f.debug_struct("Foo"); //! //! // PWrapper is a wrapper for std types, which defines the formatter methods for them. diff --git a/const_format/src/fmt/str_writer.rs b/const_format/src/fmt/str_writer.rs index 3762d60..97aae75 100644 --- a/const_format/src/fmt/str_writer.rs +++ b/const_format/src/fmt/str_writer.rs @@ -455,8 +455,6 @@ impl StrWriter { } } -#[cfg_attr(feature = "docsrs", doc(cfg(feature = "const_generics")))] -#[cfg(feature = "const_generics")] impl StrWriter<[u8; N]> { /// Casts a `&StrWriter<[u8; N]>` to a `&StrWriter<[u8]>`, /// for calling methods defined on `StrWriter<[u8]>` (most of them). diff --git a/const_format/src/lib.rs b/const_format/src/lib.rs index c8e8af6..9f51418 100644 --- a/const_format/src/lib.rs +++ b/const_format/src/lib.rs @@ -257,13 +257,9 @@ //! allowing the `as_bytes_alt` methods and `slice_up_to_len_alt` methods to run //! in constant time, rather than linear time proportional to the truncated part of the slice. //! -//! "const_generics": -//! Enables impls that use const generics, currently only used for ergonomics. -//! Use this when const generics are usable in stable Rust. -//! -//! "nightly_const_generics": -//! Enables impls that use const generics, currently only used for ergonomics. -//! This requires a nightly Rust compiler. +//! - "const_generics": Requires Rust 1.51.0. +//! Uses const generics in the implementation of the [`concatcp`] and [`formatcp`] +//! macros to output less code. //! //! //! @@ -353,6 +349,9 @@ pub mod panicking; mod pargument; +#[cfg(feature = "const_generics")] +mod const_generic_concatcp; + #[cfg_attr(feature = "docsrs", doc(cfg(feature = "fmt")))] #[cfg(feature = "fmt")] pub mod utils; @@ -421,6 +420,9 @@ pub mod pmr { result::Result::{self, Err, Ok}, }; + #[cfg(feature = "const_generics")] + pub use crate::const_generic_concatcp::__priv_concatenate; + #[cfg(feature = "fmt")] pub use crate::{ fmt::{ComputeStrLength, Error, Formatter, StrWriter, StrWriterMut, ToResult}, diff --git a/const_format/src/macros/fmt_macros.rs b/const_format/src/macros/fmt_macros.rs index 1cddcae..700dab4 100644 --- a/const_format/src/macros/fmt_macros.rs +++ b/const_format/src/macros/fmt_macros.rs @@ -63,9 +63,10 @@ macro_rules! concatcp { #[doc(hidden)] #[macro_export] +#[cfg(not(feature = "const_generics"))] macro_rules! __concatcp_inner { ($variables:ident) => {{ - const ARR_LEN: usize = $variables.0; + const ARR_LEN: usize = $crate::pmr::PArgument::calc_len($variables); const CONCAT_ARR: &$crate::pmr::LenAndArray<[u8; ARR_LEN]> = { use $crate::{__write_pvariant, pmr::PVariant}; @@ -75,7 +76,7 @@ macro_rules! __concatcp_inner { array: [0u8; ARR_LEN], }; - let input = $variables.1; + let input = $variables; $crate::__for_range! { outer_i in 0..input.len() => let current = &input[outer_i]; @@ -100,6 +101,28 @@ macro_rules! __concatcp_inner { }}; } +#[doc(hidden)] +#[macro_export] +#[cfg(feature = "const_generics")] +macro_rules! __concatcp_inner { + ($variables:ident) => {{ + const ARR_LEN: usize = $crate::pmr::PArgument::calc_len($variables); + + const CONCAT_ARR: &$crate::pmr::LenAndArray<[u8; ARR_LEN]> = + &$crate::pmr::__priv_concatenate($variables); + + #[allow(clippy::transmute_ptr_to_ptr)] + const CONCAT_STR: &str = unsafe { + // This transmute truncates the length of the array to the amound of written bytes. + let slice = + $crate::pmr::transmute::<&[u8; ARR_LEN], &[u8; CONCAT_ARR.len]>(&CONCAT_ARR.array); + + $crate::pmr::transmute::<&[u8], &str>(slice) + }; + CONCAT_STR + }}; +} + //////////////////////////////////////////////////////////////////////////////// /// Formats constants of primitive types into a `&'static str` @@ -120,7 +143,7 @@ macro_rules! __concatcp_inner { /// - Use constants from scope as arguments: `formatcp!("{FOO}")`, /// equivalent to the [`format_args_implicits` RFC] /// -/// - Use Debug-like formatting (eg: `formatcp!("{:?}", "hello" ): +/// - Use Debug-like formatting (eg: `formatcp!("{:?}", "hello" )`: /// Similar to how Debug formatting in the standard library works, /// except that it does not escape unicode characters.` /// diff --git a/const_format/src/marker_traits/format_marker.rs b/const_format/src/marker_traits/format_marker.rs index 921cf14..672c691 100644 --- a/const_format/src/marker_traits/format_marker.rs +++ b/const_format/src/marker_traits/format_marker.rs @@ -113,7 +113,6 @@ pub trait FormatMarker { /// used as the [`Kind`] associated type in [`FormatMarker`]. /// /// [`Kind`]: ./trait.FormatMarker.html#associatedtype.Kind -/// [`FormatMarker`]: ./trait.FormatMarker.html /// pub struct IsArrayKind(PhantomData); @@ -121,7 +120,6 @@ pub struct IsArrayKind(PhantomData); /// used as the [`Kind`] associated type in [`FormatMarker`]. /// /// [`Kind`]: ./trait.FormatMarker.html#associatedtype.Kind -/// [`FormatMarker`]: ./trait.FormatMarker.html /// pub struct IsStdKind; @@ -129,7 +127,6 @@ pub struct IsStdKind; /// used as the [`Kind`] associated type in [`FormatMarker`]. /// /// [`Kind`]: ./trait.FormatMarker.html#associatedtype.Kind -/// [`FormatMarker`]: ./trait.FormatMarker.html /// pub struct IsNotStdKind; @@ -168,6 +165,8 @@ macro_rules! std_kind_impls { /// `T` is `::This`: /// The `R` type after removing all layers of references. /// +/// `R`: a type that implements [`FormatMarker`]. +/// /// # Coerce Method /// /// The `coerce` method is what does the conversion from a `&T` depending on @@ -179,12 +178,6 @@ macro_rules! std_kind_impls { /// /// - [`IsNotStdKind`]: the reference is simply returned as a `&T`. /// -/// [`IsArrayKind`]: ./struct.IsArrayKind.html -/// [`IsStdKind`]: ./struct.IsStdKind.html -/// [`IsNotStdKind`]: ./struct.IsNotStdKind.html -/// -/// [`PWrapper`]: ../struct.PWrapper.html -/// #[allow(clippy::type_complexity)] pub struct IsAFormatMarker( PhantomData<( @@ -249,17 +242,6 @@ impl IsAFormatMarker { ///////////////////////////////////////////////////////////////////////////// -macro_rules! array_impls { - ($($len:literal),* $(,)* ) => ( - $( - impl FormatMarker for [T; $len] { - type Kind = IsArrayKind; - type This = Self; - } - )* - ) -} - std_kind_impls! { i8, u8, i16, u16, @@ -283,11 +265,9 @@ impl IsAFormatMarker { } } -array_impls! { - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, - 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, - 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, +impl FormatMarker for [T; N] { + type Kind = IsArrayKind; + type This = Self; } impl FormatMarker for [T] { diff --git a/const_format/src/marker_traits/write_marker.rs b/const_format/src/marker_traits/write_marker.rs index c924906..e9293a6 100644 --- a/const_format/src/marker_traits/write_marker.rs +++ b/const_format/src/marker_traits/write_marker.rs @@ -163,6 +163,8 @@ where /// `T` is `::This`: /// The `R` type after removing all layers of references. /// +/// `R`: A type that implements `WriteMarker`. +/// /// # Coerce Method /// /// The `coerce` method is what does the conversion from a `&mut T` diff --git a/const_format/src/pargument.rs b/const_format/src/pargument.rs index 23a8d12..2f0edc8 100644 --- a/const_format/src/pargument.rs +++ b/const_format/src/pargument.rs @@ -14,6 +14,20 @@ pub struct PArgument { pub fmt_flags: FormattingFlags, } +impl PArgument { + /// Calculates the length of the string after adding up all the PArguments + pub const fn calc_len(mut args: &[PArgument]) -> usize { + let mut sum = 0; + + while let [curr, rem @ ..] = args { + args = rem; + sum += curr.fmt_len; + } + + sum + } +} + #[doc(hidden)] pub enum PVariant { Str(&'static str), diff --git a/const_format/tests/fmt_tests/str_writer_methods.rs b/const_format/tests/fmt_tests/str_writer_methods.rs index 17d4c76..3dbd833 100644 --- a/const_format/tests/fmt_tests/str_writer_methods.rs +++ b/const_format/tests/fmt_tests/str_writer_methods.rs @@ -337,7 +337,7 @@ fn write_str_debug() { while let Err(_) = w.write_str_range_debug(ALL_ASCII, gen_range()) {} let end = w.len(); start + 1..end - 1 - }; + } #[cfg(not(miri))] const ITERATIONS: usize = 1000; diff --git a/const_format_proc_macros/Cargo.toml b/const_format_proc_macros/Cargo.toml index 8efc0d6..f6da544 100644 --- a/const_format_proc_macros/Cargo.toml +++ b/const_format_proc_macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "const_format_proc_macros" -version = "0.2.8" +version = "0.2.14" authors = ["rodrimati1992 "] edition = "2018" license = "Zlib" diff --git a/const_format_proc_macros/src/format_macro.rs b/const_format_proc_macros/src/format_macro.rs index 93186fa..661605e 100644 --- a/const_format_proc_macros/src/format_macro.rs +++ b/const_format_proc_macros/src/format_macro.rs @@ -26,21 +26,12 @@ pub(crate) fn concatcp_impl(value: ExprArgs) -> Result Result"] edition = "2018" [features] -nightly = ["const_format/assert"] +nightly = ["const_format/assert", "const_format/const_generics"] [dependencies] const_format = {path = "../const_format/"} \ No newline at end of file