strval

Check-in Differences
Login

Check-in Differences

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Difference From strval-0.3.1 To strval-0.3.2

2025-08-03
02:40
Make some Controllers Clone:able. check-in: 357a5aad04 user: jan tags: trunk
00:42
Release maintenance. check-in: d2549d3bcd user: jan tags: strval-0.3.2, trunk
00:41
Some FromStr implementations were missing validation calls. check-in: 1fe47acddf user: jan tags: trunk
2025-07-30
00:47
Add missing date. check-in: 8cf0fe0bcc user: jan tags: strval-0.3.1, trunk
00:45
Implement Display for data types. check-in: e1141e3da7 user: jan tags: trunk

Changes to Cargo.toml.
1
2
3

4
5
6
7
8
9
10
1
2

3
4
5
6
7
8
9
10


-
+







[package]
name = "strval"
version = "0.3.1"
version = "0.3.2"
edition = "2024"
license = "0BSD"
# https://crates.io/category_slugs
categories = ["text-processing"]
keywords = ["parsing", "string", "rusqlite"]
repository = "https://repos.qrnch.tech/pub/strval"
description = "Parse strings into values"
Changes to src/binu64count.rs.
71
72
73
74
75
76
77
78




79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105




106
107
108
109
110
111
112
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116
117
118
119







-
+
+
+
+








+










-
+







-
+
+
+
+








impl<C> fmt::Display for BinU64Count<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for BinU64Count<C> {
impl<C> FromStr for BinU64Count<C>
where
  C: Controller<Type = u64>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let val = parse_size::Config::default()
      .with_binary()
      .with_byte_suffix(ByteSuffix::Deny)
      .parse_size(s)
      .map_err(|e| Error::Invalid(e.to_string()))?;
    C::validate(&val)?;
    Ok(Self {
      sval: s.to_string(),
      val,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl ToSql for BinU64Count {
impl<C> ToSql for BinU64Count<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    self.sval.to_sql()
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl FromSql for BinU64Count {
impl<C> FromSql for BinU64Count<C>
where
  C: Controller<Type = u64>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
166
167
168
169
170
171
172






173
174
175
176
177
178
179
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192







+
+
+
+
+
+







  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob() {
    let mut val = BinU64Count::<SomeU64Bound>::default();

    let _v = val.set("512k").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob_parsed() {
    let _v = "512k".parse::<BinU64Count<SomeU64Bound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/binu64size.rs.
71
72
73
74
75
76
77
78




79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96
97

98
99
100
101
102
103
104
105




106
107
108
109
110
111
112
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116
117
118
119







-
+
+
+
+








+










-
+







-
+
+
+
+








impl<C> fmt::Display for BinU64Size<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for BinU64Size<C> {
impl<C> FromStr for BinU64Size<C>
where
  C: Controller<Type = u64>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let val = parse_size::Config::default()
      .with_binary()
      .with_byte_suffix(ByteSuffix::Require)
      .parse_size(s)
      .map_err(|e| Error::Invalid(e.to_string()))?;
    C::validate(&val)?;
    Ok(Self {
      sval: s.to_string(),
      val,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl ToSql for BinU64Size {
impl<C> ToSql for BinU64Size<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    self.sval.to_sql()
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl FromSql for BinU64Size {
impl<C> FromSql for BinU64Size<C>
where
  C: Controller<Type = u64>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
167
168
169
170
171
172
173





174
175
176
177
178
179
180
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192







+
+
+
+
+







  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob() {
    let mut val = BinU64Size::<SomeU64Bound>::default();

    let _v = val.set("512KB").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob_parsed() {
    let _val = "512KB".parse::<BinU64Size<SomeU64Bound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/binusizecount.rs.
71
72
73
74
75
76
77
78




79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107




108
109
110
111
112
113
114
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
118
119
120
121







-
+
+
+
+










+










-
+







-
+
+
+
+








impl<C> fmt::Display for BinUsizeCount<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for BinUsizeCount<C> {
impl<C> FromStr for BinUsizeCount<C>
where
  C: Controller<Type = usize>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let val = parse_size::Config::default()
      .with_binary()
      .with_byte_suffix(ByteSuffix::Deny)
      .parse_size(s)
      .map_err(|e| Error::Invalid(e.to_string()))?;
    let val =
      usize::try_from(val).map_err(|e| Error::OutOfBounds(e.to_string()))?;
    C::validate(&val)?;
    Ok(Self {
      sval: s.to_string(),
      val,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl ToSql for BinUsizeCount {
impl<C> ToSql for BinUsizeCount<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    self.sval.to_sql()
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl FromSql for BinUsizeCount {
impl<C> FromSql for BinUsizeCount<C>
where
  C: Controller<Type = usize>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
168
169
170
171
172
173
174






175
176
177
178
179
180
181
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194







+
+
+
+
+
+







  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob() {
    let mut val = BinUsizeCount::<SomeUsizeBound>::default();

    let _v = val.set("512k").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob_parsed() {
    let _val = "512k".parse::<BinUsizeCount<SomeUsizeBound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/binusizesize.rs.
71
72
73
74
75
76
77
78




79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107




108
109
110
111
112
113
114
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
118
119
120
121







-
+
+
+
+










+










-
+







-
+
+
+
+








impl<C> fmt::Display for BinUsizeSize<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for BinUsizeSize<C> {
impl<C> FromStr for BinUsizeSize<C>
where
  C: Controller<Type = usize>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let val = parse_size::Config::default()
      .with_binary()
      .with_byte_suffix(ByteSuffix::Require)
      .parse_size(s)
      .map_err(|e| Error::Invalid(e.to_string()))?;
    let val =
      usize::try_from(val).map_err(|e| Error::OutOfBounds(e.to_string()))?;
    C::validate(&val)?;
    Ok(Self {
      sval: s.to_string(),
      val,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl ToSql for BinUsizeSize {
impl<C> ToSql for BinUsizeSize<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    self.sval.to_sql()
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl FromSql for BinUsizeSize {
impl<C> FromSql for BinUsizeSize<C>
where
  C: Controller<Type = usize>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
169
170
171
172
173
174
175





176
177
178
179
180
181
182
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194







+
+
+
+
+







  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob() {
    let mut val = BinUsizeSize::<SomeUsizeBound>::default();

    let _v = val.set("512KB").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob_parsed() {
    let _val = "512KB".parse::<BinUsizeSize<SomeUsizeBound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/decu64count.rs.
71
72
73
74
75
76
77
78




79
80
81
82
83
84
85
86

87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105




106
107
108
109
110
111
112
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108

109
110
111
112
113
114
115
116
117
118
119







-
+
+
+
+








+


















-
+
+
+
+








impl<C> fmt::Display for DecU64Count<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for DecU64Count<C> {
impl<C> FromStr for DecU64Count<C>
where
  C: Controller<Type = u64>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let val = parse_size::Config::default()
      .with_decimal()
      .with_byte_suffix(ByteSuffix::Deny)
      .parse_size(s)
      .map_err(|e| Error::Invalid(e.to_string()))?;
    C::validate(&val)?;
    Ok(Self {
      sval: s.to_string(),
      val,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> ToSql for DecU64Count<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    self.sval.to_sql()
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> FromSql for DecU64Count<C> {
impl<C> FromSql for DecU64Count<C>
where
  C: Controller<Type = u64>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
165
166
167
168
169
170
171






172
173
174
175
176
177
178
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191







+
+
+
+
+
+







  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob() {
    let mut val = DecU64Count::<SomeU64Bound>::default();

    let _v = val.set("512k").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob_parsed() {
    let _val = "512k".parse::<DecU64Count<SomeU64Bound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/decu64size.rs.
70
71
72
73
74
75
76
77




78
79
80
81
82
83
84
85

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104




105
106
107
108
109
110
111
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

108
109
110
111
112
113
114
115
116
117
118







-
+
+
+
+








+


















-
+
+
+
+








impl<C> fmt::Display for DecU64Size<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for DecU64Size<C> {
impl<C> FromStr for DecU64Size<C>
where
  C: Controller<Type = u64>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let val = parse_size::Config::default()
      .with_decimal()
      .with_byte_suffix(ByteSuffix::Require)
      .parse_size(s)
      .map_err(|e| Error::Invalid(e.to_string()))?;
    C::validate(&val)?;
    Ok(Self {
      sval: s.to_string(),
      val,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> ToSql for DecU64Size<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    self.sval.to_sql()
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> FromSql for DecU64Size<C> {
impl<C> FromSql for DecU64Size<C>
where
  C: Controller<Type = u64>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
164
165
166
167
168
169
170






171
172
173
174
175
176
177
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190







+
+
+
+
+
+







  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob() {
    let mut val = DecU64Size::<SomeU64Bound>::default();

    let _v = val.set("512kb").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob_parsed() {
    let _val = "512kb".parse::<DecU64Size<SomeU64Bound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/decusizecount.rs.
71
72
73
74
75
76
77
78




79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107




108
109
110
111
112
113
114
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102

103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
118
119
120
121







-
+
+
+
+










+










-
+







-
+
+
+
+








impl<C> fmt::Display for DecUsizeCount<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for DecUsizeCount<C> {
impl<C> FromStr for DecUsizeCount<C>
where
  C: Controller<Type = usize>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let val = parse_size::Config::default()
      .with_decimal()
      .with_byte_suffix(ByteSuffix::Deny)
      .parse_size(s)
      .map_err(|e| Error::Invalid(e.to_string()))?;
    let val =
      usize::try_from(val).map_err(|e| Error::OutOfBounds(e.to_string()))?;
    C::validate(&val)?;
    Ok(Self {
      sval: s.to_string(),
      val,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl ToSql for DecUsizeCount {
impl<C> ToSql for DecUsizeCount<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    self.sval.to_sql()
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl FromSql for DecUsizeCount {
impl<C> FromSql for DecUsizeCount<C>
where
  C: Controller<Type = usize>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
168
169
170
171
172
173
174






175
176
177
178
179
180
181
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194







+
+
+
+
+
+







  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob() {
    let mut val = DecUsizeCount::<SomeUsizeBound>::default();

    let _v = val.set("512k").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob_parsed() {
    let _val = "512k".parse::<DecUsizeCount<SomeUsizeBound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/decusizesize.rs.
70
71
72
73
74
75
76
77




78
79
80
81
82
83
84
85
86
87

88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106




107
108
109
110
111
112
113
70
71
72
73
74
75
76

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109

110
111
112
113
114
115
116
117
118
119
120







-
+
+
+
+










+


















-
+
+
+
+








impl<C> fmt::Display for DecUsizeSize<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for DecUsizeSize<C> {
impl<C> FromStr for DecUsizeSize<C>
where
  C: Controller<Type = usize>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let val = parse_size::Config::default()
      .with_decimal()
      .with_byte_suffix(ByteSuffix::Require)
      .parse_size(s)
      .map_err(|e| Error::Invalid(e.to_string()))?;
    let val =
      usize::try_from(val).map_err(|e| Error::OutOfBounds(e.to_string()))?;
    C::validate(&val)?;
    Ok(Self {
      sval: s.to_string(),
      val,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> ToSql for DecUsizeSize<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    self.sval.to_sql()
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> FromSql for DecUsizeSize<C> {
impl<C> FromSql for DecUsizeSize<C>
where
  C: Controller<Type = usize>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
166
167
168
169
170
171
172






173
174
175
176
177
178
179
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192







+
+
+
+
+
+







  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob() {
    let mut val = DecUsizeSize::<SomeUsizeBound>::default();

    let _v = val.set("512kb").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"Must be 10 - 256K\")")]
  fn oob_parsed() {
    let _val = "512kb".parse::<DecUsizeSize<SomeUsizeBound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/dur.rs.
76
77
78
79
80
81
82
83




84
85
86
87
88
89
90

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109




110
111
112
113
114
115
116
76
77
78
79
80
81
82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

113
114
115
116
117
118
119
120
121
122
123







-
+
+
+
+







+


















-
+
+
+
+








impl<C> fmt::Display for Dur<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for Dur<C> {
impl<C> FromStr for Dur<C>
where
  C: Controller<Type = Duration>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    let dur = s
      .parse::<jiff::SignedDuration>()
      .map_err(|e| Error::Invalid(e.to_string()))?;
    let dur = dur.unsigned_abs();
    C::validate(&dur)?;
    Ok(Self {
      sval: s.to_string(),
      val: dur,
      _marker: PhantomData
    })
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> ToSql for Dur<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    Ok(ToSqlOutput::from(self.as_ref()))
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> FromSql for Dur<C> {
impl<C> FromSql for Dur<C>
where
  C: Controller<Type = Duration>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
174
175
176
177
178
179
180





181
182
183
184
185
186
187
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199







+
+
+
+
+







  #[should_panic(expected = "OutOfBounds(\"1s..60s\")")]
  fn oob() {
    let mut val = Dur::<SomeDurBound>::default();

    let _v = val.set("100ms").unwrap();
  }

  #[test]
  #[should_panic(expected = "OutOfBounds(\"1s..60s\")")]
  fn oob_parsed() {
    let _val = "1ms".parse::<Dur<SomeDurBound>>().unwrap();
  }

  #[cfg(feature = "rusqlite")]
  fn memdb() -> Result<Connection, rusqlite::Error> {
    let conn = Connection::open_in_memory()?;
    conn.execute_batch(
      "CREATE TABLE tbl (id INTEGER PRIMARY KEY, txtval TEXT)"
    )?;
Changes to src/relabslim.rs.
107
108
109
110
111
112
113
114




115
116
117
118
119
120


121
122
123

124
125
126
127
128
129
130


131
132
133

134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151




152
153
154
155
156
157
158
107
108
109
110
111
112
113

114
115
116
117
118
119
120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
135
136
137
138
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

158
159
160
161
162
163
164
165
166
167
168







-
+
+
+
+






+
+


-
+







+
+


-
+

















-
+
+
+
+








impl<C> fmt::Display for RelAbsLim<C> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.sval)
  }
}

impl<C> FromStr for RelAbsLim<C> {
impl<C> FromStr for RelAbsLim<C>
where
  C: Controller<Type = Lim>
{
  type Err = Error;

  fn from_str(s: &str) -> Result<Self, Self::Err> {
    if let Some(s) = s.strip_suffix("%") {
      let f = s.parse::<f32>().unwrap();
      let f = f / 100.0;
      let val = Lim::Rel(f);
      C::validate(&val)?;
      Ok(Self {
        sval: s.to_string(),
        val: Lim::Rel(f),
        val,
        _marker: PhantomData
      })
    } else {
      let val = parse_size::Config::default()
        .with_binary()
        .parse_size(s)
        .map_err(|e| Error::Invalid(e.to_string()))?;
      let val = Lim::Abs(val);
      C::validate(&val)?;
      Ok(Self {
        sval: s.to_string(),
        val: Lim::Abs(val),
        val,
        _marker: PhantomData
      })
    }
  }
}


#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> ToSql for RelAbsLim<C> {
  fn to_sql(&self) -> Result<ToSqlOutput<'_>, rusqlite::Error> {
    Ok(ToSqlOutput::from(self.as_ref()))
  }
}

#[cfg(feature = "rusqlite")]
#[cfg_attr(docsrs, doc(cfg(feature = "rusqlite")))]
impl<C> FromSql for RelAbsLim<C> {
impl<C> FromSql for RelAbsLim<C>
where
  C: Controller<Type = Lim>
{
  #[inline]
  fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
    let s = String::column_result(value)?;
    s.parse::<Self>()
      .map_err(|e| FromSqlError::Other(Box::new(e)))
  }
}
Changes to www/changelog.md.
1
2
3
4
5
6
7

8
9
10
11
12
13
14










15
16
17
18
19
20
21
1
2
3
4
5
6

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31






-
+







+
+
+
+
+
+
+
+
+
+







# Change Log

⚠️  indicates a breaking change.

## [Unreleased]

[Details](/vdiff?from=strval-0.3.1&to=trunk)
[Details](/vdiff?from=strval-0.3.2&to=trunk)

### Added

### Changed

### Removed

---

## [0.3.2] - 2025-08-03

[Details](/vdiff?from=strval-0.3.1&to=strval-0.3.2)

### Changed

- Bugfix: Add missing parse validation to some `FromStr` implementations.

---

## [0.3.1] - 2025-07-30

[Details](/vdiff?from=strval-0.3.0&to=strval-0.3.1)

### Added