display_more/display_option/mod.rs
1// Copyright 2021 Datafuse Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://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,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt;
16
17/// Wrapper that implements `Display` for `Option<T>` using either `Display` or `Debug` formatting.
18///
19/// It outputs a literal string `"None"` if it is None. Otherwise it invokes the stored
20/// formatting function for T.
21pub struct DisplayOption<'a, T> {
22 inner: &'a Option<T>,
23 fmt_fn: fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result,
24}
25
26impl<T> fmt::Display for DisplayOption<'_, T> {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match &self.inner {
29 None => write!(f, "None"),
30 Some(x) => (self.fmt_fn)(x, f),
31 }
32 }
33}
34
35/// Implement `Display` for `Option<T>` if T is `Display`.
36///
37/// It outputs a literal string `"None"` if it is None. Otherwise it invokes the Display
38/// implementation for T.
39///
40/// # Example
41///
42/// ```rust
43/// use display_more::DisplayOptionExt;
44///
45/// let option = Some(1);
46/// assert_eq!(option.display().to_string(), "1");
47/// ```
48pub trait DisplayOptionExt<'a, T: fmt::Display> {
49 fn display(&'a self) -> DisplayOption<'a, T>;
50}
51
52impl<T> DisplayOptionExt<'_, T> for Option<T>
53where T: fmt::Display
54{
55 fn display(&self) -> DisplayOption<T> {
56 DisplayOption {
57 inner: self,
58 fmt_fn: <T as fmt::Display>::fmt,
59 }
60 }
61}
62
63/// Extension trait to format `Option<T>` using `Debug` formatting.
64///
65/// # Example
66///
67/// ```rust
68/// use display_more::DisplayDebugOptionExt;
69///
70/// let option = Some("hello");
71/// assert_eq!(option.display_debug().to_string(), "\"hello\"");
72/// ```
73pub trait DisplayDebugOptionExt<'a, T: fmt::Debug> {
74 fn display_debug(&'a self) -> DisplayOption<'a, T>;
75}
76
77impl<T> DisplayDebugOptionExt<'_, T> for Option<T>
78where T: fmt::Debug
79{
80 fn display_debug(&self) -> DisplayOption<T> {
81 DisplayOption {
82 inner: self,
83 fmt_fn: <T as fmt::Debug>::fmt,
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_display_option() {
94 let option = Some(1);
95 assert_eq!(option.display().to_string(), "1");
96 }
97
98 #[test]
99 fn test_display_option_none() {
100 let option = None::<u64>;
101 assert_eq!(option.display().to_string(), "None");
102 }
103
104 #[test]
105 fn test_debug_option() {
106 assert_eq!(Some(1).display_debug().to_string(), "1");
107 assert_eq!(None::<u64>.display_debug().to_string(), "None");
108 // Debug adds quotes around strings
109 assert_eq!(Some("hello").display_debug().to_string(), "\"hello\"");
110 // Vec has Debug but not Display
111 assert_eq!(Some(vec![1, 2, 3]).display_debug().to_string(), "[1, 2, 3]");
112 }
113}