* Add dependency on the `thiserror` crate
* Add a global `Error` type, but also `maps::Error` and
`providers::combined::MergeError` for convenience
* Add matching `Result` types that default to the respective `Error`
type
* Refactor code to yield all kinds of error variants
* Add FIXMEs where library errors still need to be handled
* Remove documentation that explained why `None` was returned, this is
captured in the error now
For example, if there are 24 valid pollen samples and 20 valid air
quality items, the maximum pollen sample could be de 23th, but the
resulting combined series will only cover 20 items. So, it is should not
return that, but only look in the first 20 pollen samples for the
maximum sample.
If the sample/item series are empty, the function already returns
`None`, so the tuple values are always `Some(_)` which makes the
`Option` type redundant.
* Check that merging fails if the samples/items are too far apart
* Check that nothing is returned if either of the lists is empty
* Check that if either series is shifted, they are merged correctly
* Make the combined provider keep track of the AQI and pollen maximum
value
* Extend the `Forecast` struct with the `aqi_max` and `pollen_max`
fields
* Fill the `aqi_max` and `pollen_max` fields when the PAQI metric is
selected
* Update the documentation
* Extend the tests
* Move the function `draw_position` to the maps module and split it up
* Replace and refactor `pollen_at` and `uvi_at` methods on `Maps`
by `pollen_mark` and `uvi_mark`
* Drop the `pollen_project` and `uvi_project` methods on `Maps`,
just call the `project` helper method directly
* Add `map_at` and `mark` helper methods that handle maps slicing
and drawing
* Rename `pollen_sample` and `uvi_sample` methods on `Maps` to their
plural forms
* Also, rename the map handlers to `map_address` and `map_geo`
* Use the `Europe::Amsterdam` time zone from `chrono_tz` to determine
what date/time it is in that time zone
* Parse timestamps in the rain text API relative to this date/time
* Add the `fix_items_day_boundary` function to fix up stuff if
the series of timestamps in the rain text cross the day boundary
* Use `Position` everywhere instead of latitude/longitude float values
* Implement `Partial`, `Eq` and `Hash` for `Position` so it can
part of a cache key
* Drop the `cache_key` helper function
* Rename the `address_position` function to `resolve_address`
* Add methods on `Position` for formatting latitude/longitude with
a given precision (used for URL parameters in providers)
* Also cache address geocoding requests to OSM Nomatim!
* Use the `cached` crate for an easy implementation
* Add the `cache_key` helper function to deal with floats being annoying
* Cache Buienradar get request for 5 minutes (per position/metric)
* Cache Luchtmeetnet get request for 5 minutes (per position/metric)
* Note the `Item` structs need to implement `Clone` now because
the cache will own them and Rocket will want a copy too
* Add the `csv` crate as a dependency
* Use the `Row` struct as intermediate object
* Turn the `parse_value` function into the `convert_value` function that
cannot fail