Skip to content

Commit 4ca477b

Browse files
committed
Change QueryBuilder to own all strings
1 parent caac305 commit 4ca477b

File tree

4 files changed

+45
-24
lines changed

4 files changed

+45
-24
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33
All notable changes to this project will be documented in this file.
44
This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
55

6+
## [0.4.0] - 2023-07-08
7+
8+
### Added
9+
10+
- The `QueryBuilder` now owns all string values, making it easier to pass
11+
a `QueryBuilder` value out of a function.
12+
613
## [0.3.0] - 2023-07-08
714

815
### Added

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "query-string-builder"
33
description = "A query string builder for percent encoding key-value pairs"
44
authors = ["Markus Mayer"]
5-
version = "0.3.0"
5+
version = "0.4.0"
66
edition = "2021"
77
repository = "https://github.com/sunsided/query-string-builder"
88
keywords = ["url", "query-string", "query-argument"]
@@ -11,4 +11,4 @@ readme = "README.md"
1111
license-file = "LICENSE.md"
1212

1313
[dependencies]
14-
percent-encoding = "2.3.0"
14+
percent-encoding = { version = "2.3.0", default-features = false, features = ["std"] }

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use query_string_builder::QueryString;
1111
fn main() {
1212
let qs = QueryString::new()
1313
.with_value("q", "apple")
14-
.with_opt_value("color", None)
14+
.with_opt_value("color", None::<String>)
1515
.with_opt_value("category", Some("fruits and vegetables?"));
1616

1717
assert_eq!(

src/lib.rs

Lines changed: 35 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//!
1111
//! let qs = QueryString::new()
1212
//! .with_value("q", "🍎 apple")
13-
//! .with_opt_value("color", None)
13+
//! .with_opt_value("color", None::<String>)
1414
//! .with_opt_value("category", Some("fruits and vegetables?"));
1515
//!
1616
//! assert_eq!(
@@ -44,11 +44,11 @@ const FRAGMENT: &AsciiSet = &CONTROLS.add(b' ').add(b'"').add(b'<').add(b'>').ad
4444
/// );
4545
/// ```
4646
#[derive(Debug, Default, Clone)]
47-
pub struct QueryString<'a> {
48-
pairs: Vec<Kvp<'a>>,
47+
pub struct QueryString {
48+
pairs: Vec<Kvp>,
4949
}
5050

51-
impl<'a> QueryString<'a> {
51+
impl QueryString {
5252
/// Creates a new, empty query string builder.
5353
pub fn new() -> Self {
5454
Self {
@@ -72,8 +72,11 @@ impl<'a> QueryString<'a> {
7272
/// "https://example.com/?q=%F0%9F%8D%8E%20apple&category=fruits%20and%20vegetables"
7373
/// );
7474
/// ```
75-
pub fn with_value(mut self, key: &'a str, value: &'a str) -> Self {
76-
self.pairs.push(Kvp { key, value });
75+
pub fn with_value<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
76+
self.pairs.push(Kvp {
77+
key: key.into(),
78+
value: value.into(),
79+
});
7780
self
7881
}
7982

@@ -86,15 +89,19 @@ impl<'a> QueryString<'a> {
8689
///
8790
/// let qs = QueryString::new()
8891
/// .with_opt_value("q", Some("🍎 apple"))
89-
/// .with_opt_value("f", None)
92+
/// .with_opt_value("f", None::<String>)
9093
/// .with_opt_value("category", Some("fruits and vegetables"));
9194
///
9295
/// assert_eq!(
9396
/// format!("https://example.com/{qs}"),
9497
/// "https://example.com/?q=%F0%9F%8D%8E%20apple&category=fruits%20and%20vegetables"
9598
/// );
9699
/// ```
97-
pub fn with_opt_value(self, key: &'a str, value: Option<&'a str>) -> Self {
100+
pub fn with_opt_value<K: Into<String>, V: Into<String>>(
101+
self,
102+
key: K,
103+
value: Option<V>,
104+
) -> Self {
98105
if let Some(value) = value {
99106
self.with_value(key, value)
100107
} else {
@@ -118,8 +125,11 @@ impl<'a> QueryString<'a> {
118125
/// "https://example.com/?q=apple&category=fruits%20and%20vegetables"
119126
/// );
120127
/// ```
121-
pub fn push(&mut self, key: &'a str, value: &'a str) -> &Self {
122-
self.pairs.push(Kvp { key, value });
128+
pub fn push<K: Into<String>, V: Into<String>>(&mut self, key: K, value: V) -> &Self {
129+
self.pairs.push(Kvp {
130+
key: key.into(),
131+
value: value.into(),
132+
});
123133
self
124134
}
125135

@@ -131,15 +141,19 @@ impl<'a> QueryString<'a> {
131141
/// use query_string_builder::QueryString;
132142
///
133143
/// let mut qs = QueryString::new();
134-
/// qs.push_opt("q", None);
144+
/// qs.push_opt("q", None::<String>);
135145
/// qs.push_opt("q", Some("🍎 apple"));
136146
///
137147
/// assert_eq!(
138148
/// format!("https://example.com/{qs}"),
139149
/// "https://example.com/?q=%F0%9F%8D%8E%20apple"
140150
/// );
141151
/// ```
142-
pub fn push_opt(&mut self, key: &'a str, value: Option<&'a str>) -> &Self {
152+
pub fn push_opt<K: Into<String>, V: Into<String>>(
153+
&mut self,
154+
key: K,
155+
value: Option<V>,
156+
) -> &Self {
143157
if let Some(value) = value {
144158
self.push(key, value)
145159
} else {
@@ -174,7 +188,7 @@ impl<'a> QueryString<'a> {
174188
/// "https://example.com/?q=apple&q=pear"
175189
/// );
176190
/// ```
177-
pub fn append(&mut self, mut other: QueryString<'a>) {
191+
pub fn append(&mut self, mut other: QueryString) {
178192
self.pairs.append(&mut other.pairs)
179193
}
180194

@@ -195,13 +209,13 @@ impl<'a> QueryString<'a> {
195209
/// "https://example.com/?q=apple&q=pear"
196210
/// );
197211
/// ```
198-
pub fn append_into(mut self, mut other: QueryString<'a>) -> Self {
212+
pub fn append_into(mut self, mut other: QueryString) -> Self {
199213
self.pairs.append(&mut other.pairs);
200214
self
201215
}
202216
}
203217

204-
impl<'a> Display for QueryString<'a> {
218+
impl Display for QueryString {
205219
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
206220
if self.pairs.is_empty() {
207221
return Ok(());
@@ -214,8 +228,8 @@ impl<'a> Display for QueryString<'a> {
214228
write!(
215229
f,
216230
"{key}={value}",
217-
key = utf8_percent_encode(pair.key, FRAGMENT),
218-
value = utf8_percent_encode(pair.value, FRAGMENT)
231+
key = utf8_percent_encode(&pair.key, FRAGMENT),
232+
value = utf8_percent_encode(&pair.value, FRAGMENT)
219233
)?;
220234
}
221235
Ok(())
@@ -224,9 +238,9 @@ impl<'a> Display for QueryString<'a> {
224238
}
225239

226240
#[derive(Debug, Clone)]
227-
struct Kvp<'a> {
228-
key: &'a str,
229-
value: &'a str,
241+
struct Kvp {
242+
key: String,
243+
value: String,
230244
}
231245

232246
#[cfg(test)]
@@ -267,7 +281,7 @@ mod tests {
267281
fn test_optional() {
268282
let qs = QueryString::new()
269283
.with_value("q", "celery")
270-
.with_opt_value("taste", None)
284+
.with_opt_value("taste", None::<String>)
271285
.with_opt_value("category", Some("fruits and vegetables"));
272286
assert_eq!(
273287
qs.to_string(),

0 commit comments

Comments
 (0)