Skip to main content

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}