Skip to main content Skip to main content
Pigweed's logo Pigweed
code_xml
  1. Home
  2. Reference
  3. Rust
  4. src
  5. pw_format/lib.rs

pw_format/
lib.rs

1// Copyright 2023 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14
15//! The `pw_format` crate provides format string parsing and formatting utilities to:
16//! * Parse and syntax-check format strings (`printf` and `core::fmt`).
17//! * Understand format string argument types at compile time in proc macros.
18//! * Format dynamic values according to format strings at runtime.
19//!
20//! `pw_format` is written against `std` and is not intended to be
21//! used in an embedded on-device context. Some efficiency and memory is traded for a
22//! more expressive interface that exposes the format string's syntax tree
23//! to the API client.
24//!
25//! # Proc Macros
26//!
27//! The `macros` module provides infrastructure for implementing proc macros
28//! that take format strings as arguments.
29//!
30//! # Parsing Example
31//!
32//! ```
33//! use pw_format::{
34//!     Alignment, Argument, ConversionSpec, Flag, FormatFragment, FormatString,
35//!     Length, MinFieldWidth, Precision, Primitive, Style,
36//! };
37//!
38//! let format_string =
39//!   FormatString::parse_printf("long double %+ 4.2Lf is %-03hd%%.").unwrap();
40//!
41//! assert_eq!(format_string, FormatString {
42//!   fragments: vec![
43//!       FormatFragment::Literal("long double ".to_string()),
44//!       FormatFragment::Conversion(ConversionSpec {
45//!           argument: Argument::None,
46//!           fill: ' ',
47//!           alignment: Alignment::None,
48//!           flags: [Flag::ForceSign, Flag::SpaceSign].into_iter().collect(),
49//!           min_field_width: MinFieldWidth::Fixed(4),
50//!           precision: Precision::Fixed(2),
51//!           length: Some(Length::LongDouble),
52//!           primitive: Primitive::Float,
53//!           style: Style::None,
54//!       }),
55//!       FormatFragment::Literal(" is ".to_string()),
56//!       FormatFragment::Conversion(ConversionSpec {
57//!           argument: Argument::None,
58//!           fill: ' ',
59//!           alignment: Alignment::Left,
60//!           flags: [Flag::LeftJustify, Flag::LeadingZeros]
61//!               .into_iter()
62//!               .collect(),
63//!           min_field_width: MinFieldWidth::Fixed(3),
64//!           precision: Precision::None,
65//!           length: Some(Length::Short),
66//!           primitive: Primitive::Integer,
67//!           style: Style::None,
68//!       }),
69//!       FormatFragment::Literal("%.".to_string()),
70//!   ]
71//! });
72//! ```
73//!
74//! # Runtime Formatting Example
75//!
76//! ```
77//! use pw_format::{Arg, FormatString, FormatStyle};
78//!
79//! let fmt = FormatString::parse_printf("Hello %s, code: 0x%04x!").unwrap();
80//! let output = fmt.format(
81//!     &[Arg::Str("world".to_string()), Arg::Uint(42)],
82//!     FormatStyle::Printf,
83//! );
84//! assert_eq!(output, "Hello world, code: 0x002a!");
85//! ```
86//!
87//! # Error Formatting Example
88//!
89//! When formatting strings with missing or mismatched arguments, custom error formatters
90//! implementing [`FormatError`] can be supplied:
91//!
92//! ```
93//! use pw_format::{Arg, ConversionSpec, FormatError, FormatString, FormatStyle};
94//!
95//! struct MyErrorFormatter;
96//! impl FormatError for MyErrorFormatter {
97//!     type Error = ();
98//!     fn format_error(&self, spec: &ConversionSpec, _error: &()) -> String {
99//!         format!("<[{} ERROR]>", spec.to_printf())
100//!     }
101//!     fn format_missing(&self, spec: &ConversionSpec) -> String {
102//!         format!("<[{} MISSING]>", spec.to_printf())
103//!     }
104//!     fn format_type_error(&self, spec: &ConversionSpec, _arg: &Arg) -> String {
105//!         format!("<[{} TYPE_ERROR]>", spec.to_printf())
106//!     }
107//! }
108//!
109//! let fmt = FormatString::parse_printf("Value: %d").unwrap();
110//! let output = fmt.format_with_errors(&[], FormatStyle::Printf, &MyErrorFormatter);
111//! assert_eq!(output, "Value: <[%d MISSING]>");
112//! ```
113#![deny(missing_docs)]
114
115#[cfg(feature = "proc_macro")]
116pub mod macros;
117
118mod core_fmt;
119mod format_string;
120mod parser_util;
121mod printf;
122
123pub use format_string::{
124    Alignment, Arg, Argument, ConversionSpec, Flag, FormatError, FormatFragment, FormatString,
125    FormatStyle, Length, MinFieldWidth, Precision, Primitive, Style,
126};
127
128#[cfg(test)]
129mod tests;