sql_support/repeat.rs
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use std::fmt;
6
7/// Helper type for printing repeated strings more efficiently. You should use
8/// [`repeat_display`] or one of the `repeat_sql_*` helpers to
9/// construct it.
10#[derive(Debug, Clone)]
11pub struct RepeatDisplay<'a, F> {
12 count: usize,
13 sep: &'a str,
14 fmt_one: F,
15}
16
17impl<F> fmt::Display for RepeatDisplay<'_, F>
18where
19 F: Fn(usize, &mut fmt::Formatter<'_>) -> fmt::Result,
20{
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 for i in 0..self.count {
23 if i != 0 {
24 f.write_str(self.sep)?;
25 }
26 (self.fmt_one)(i, f)?;
27 }
28 Ok(())
29 }
30}
31
32/// Construct a RepeatDisplay that will repeatedly call `fmt_one` with a formatter `count` times,
33/// separated by `sep`.
34///
35/// # Example
36///
37/// ```rust
38/// # use sql_support::repeat_display;
39/// assert_eq!(format!("{}", repeat_display(1, ",", |i, f| write!(f, "({},?)", i))),
40/// "(0,?)");
41/// assert_eq!(format!("{}", repeat_display(2, ",", |i, f| write!(f, "({},?)", i))),
42/// "(0,?),(1,?)");
43/// assert_eq!(format!("{}", repeat_display(3, ",", |i, f| write!(f, "({},?)", i))),
44/// "(0,?),(1,?),(2,?)");
45/// ```
46#[inline]
47pub fn repeat_display<F>(count: usize, sep: &str, fmt_one: F) -> RepeatDisplay<'_, F>
48where
49 F: Fn(usize, &mut fmt::Formatter<'_>) -> fmt::Result,
50{
51 RepeatDisplay {
52 count,
53 sep,
54 fmt_one,
55 }
56}
57
58/// Returns a value that formats as `count` instances of `?` separated by commas.
59///
60/// # Example
61///
62/// ```rust
63/// # use sql_support::repeat_sql_vars;
64/// assert_eq!(format!("{}", repeat_sql_vars(0)), "");
65/// assert_eq!(format!("{}", repeat_sql_vars(1)), "?");
66/// assert_eq!(format!("{}", repeat_sql_vars(2)), "?,?");
67/// assert_eq!(format!("{}", repeat_sql_vars(3)), "?,?,?");
68/// ```
69pub fn repeat_sql_vars(count: usize) -> impl fmt::Display {
70 repeat_display(count, ",", |_, f| write!(f, "?"))
71}
72
73/// Returns a value that formats as `count` instances of `(?)` separated by commas.
74///
75/// # Example
76///
77/// ```rust
78/// # use sql_support::repeat_sql_values;
79/// assert_eq!(format!("{}", repeat_sql_values(0)), "");
80/// assert_eq!(format!("{}", repeat_sql_values(1)), "(?)");
81/// assert_eq!(format!("{}", repeat_sql_values(2)), "(?),(?)");
82/// assert_eq!(format!("{}", repeat_sql_values(3)), "(?),(?),(?)");
83/// ```
84///
85pub fn repeat_sql_values(count: usize) -> impl fmt::Display {
86 // We could also implement this as `repeat_sql_multi_values(count, 1)`,
87 // but this is faster and no less clear IMO.
88 repeat_display(count, ",", |_, f| write!(f, "(?)"))
89}
90
91/// Returns a value that formats as `num_values` instances of `(?,?,?,...)` (where there are
92/// `vars_per_value` question marks separated by commas in between the `?`s).
93///
94/// Panics if `vars_per_value` is zero (however, `num_values` is allowed to be zero).
95///
96/// # Example
97///
98/// ```rust
99/// # use sql_support::repeat_multi_values;
100/// assert_eq!(format!("{}", repeat_multi_values(0, 2)), "");
101/// assert_eq!(format!("{}", repeat_multi_values(1, 5)), "(?,?,?,?,?)");
102/// assert_eq!(format!("{}", repeat_multi_values(2, 3)), "(?,?,?),(?,?,?)");
103/// assert_eq!(format!("{}", repeat_multi_values(3, 1)), "(?),(?),(?)");
104/// ```
105pub fn repeat_multi_values(num_values: usize, vars_per_value: usize) -> impl fmt::Display {
106 assert_ne!(
107 vars_per_value, 0,
108 "Illegal value for `vars_per_value`, must not be zero"
109 );
110 repeat_display(num_values, ",", move |_, f| {
111 write!(f, "({})", repeat_sql_vars(vars_per_value))
112 })
113}