Extract a numeric field value from a msgpack map row.
(row: &[u8], field: &str)
| 124 | |
| 125 | /// Extract a numeric field value from a msgpack map row. |
| 126 | fn extract_number(row: &[u8], field: &str) -> Option<f64> { |
| 127 | use nodedb_query::msgpack_scan::reader; |
| 128 | |
| 129 | let try_field = |name: &str| -> Option<f64> { |
| 130 | let (start, _end) = nodedb_query::msgpack_scan::extract_field(row, 0, name)?; |
| 131 | if let Some(i) = reader::read_i64(row, start) { |
| 132 | return Some(i as f64); |
| 133 | } |
| 134 | if let Some(f) = reader::read_f64(row, start) { |
| 135 | return Some(f); |
| 136 | } |
| 137 | // Try parsing string as number. |
| 138 | reader::read_str(row, start).and_then(|s| s.parse().ok()) |
| 139 | }; |
| 140 | |
| 141 | if field == "*" { |
| 142 | return Some(1.0); |
| 143 | } |
| 144 | |
| 145 | // Exact match. |
| 146 | if let Some(v) = try_field(field) { |
| 147 | return Some(v); |
| 148 | } |
| 149 | |
| 150 | // Suffix match. |
| 151 | let suffix = format!(".{field}"); |
| 152 | let (count, mut pos) = nodedb_query::msgpack_scan::reader::map_header(row, 0)?; |
| 153 | for _ in 0..count { |
| 154 | let key = nodedb_query::msgpack_scan::reader::read_str(row, pos)?; |
| 155 | let key_end = nodedb_query::msgpack_scan::reader::skip_value(row, pos)?; |
| 156 | let val_end = nodedb_query::msgpack_scan::reader::skip_value(row, key_end)?; |
| 157 | if key.ends_with(&suffix) { |
| 158 | if let Some(i) = nodedb_query::msgpack_scan::reader::read_i64(row, key_end) { |
| 159 | return Some(i as f64); |
| 160 | } |
| 161 | if let Some(f) = nodedb_query::msgpack_scan::reader::read_f64(row, key_end) { |
| 162 | return Some(f); |
| 163 | } |
| 164 | if let Some(s) = nodedb_query::msgpack_scan::reader::read_str(row, key_end) { |
| 165 | return s.parse().ok(); |
| 166 | } |
| 167 | } |
| 168 | pos = val_end; |
| 169 | } |
| 170 | None |
| 171 | } |
| 172 | |
| 173 | /// Read a msgpack value at [start..end) as a display string. |
| 174 | fn read_value_as_string(bytes: &[u8], start: usize, end: usize) -> String { |
no test coverage detected