stac_async/
io.rs

1use crate::{Error, Result};
2use serde::{de::DeserializeOwned, Serialize};
3use stac::Href;
4use std::path::Path;
5use url::Url;
6
7/// Reads a STAC value from an href.
8///
9/// The href can be a url or a filesystem path.
10///
11/// # Examples
12///
13/// ```
14/// # tokio_test::block_on(async {
15/// let item: stac::Item = stac_async::read("examples/simple-item.json").await.unwrap();
16/// # })
17/// ```
18pub async fn read<T>(href: impl ToString) -> Result<T>
19where
20    T: DeserializeOwned + Href,
21{
22    let href = href.to_string();
23    let mut value: T = read_json(&href).await?;
24    value.set_href(href);
25    Ok(value)
26}
27
28/// Reads any deserializable value from an href.
29///
30/// The href can be a url or a filesystem path.
31///
32/// # Examples
33///
34/// ```
35/// # tokio_test::block_on(async {
36/// let item: stac::Item = stac_async::read_json("examples/simple-item.json").await.unwrap();
37/// # })
38/// ```
39pub async fn read_json<T>(href: &str) -> Result<T>
40where
41    T: DeserializeOwned,
42{
43    if let Some(url) = stac::href_to_url(href) {
44        read_json_from_url(url).await
45    } else {
46        read_json_from_path(href).await
47    }
48}
49
50/// Writes any serializable value to a path.
51///
52/// # Examples
53///
54/// ```no_run
55/// let item = stac::Item::new("an-id");
56/// # tokio_test::block_on(async {
57/// let value = stac_async::write_json_to_path("item.json", item).await.unwrap();
58/// # })
59/// ```
60pub async fn write_json_to_path(path: impl AsRef<Path>, value: impl Serialize) -> Result<()> {
61    let string = serde_json::to_string_pretty(&value)?;
62    tokio::fs::write(path, string).await.map_err(Error::from)
63}
64
65async fn read_json_from_url<T>(url: Url) -> Result<T>
66where
67    T: DeserializeOwned,
68{
69    let response = reqwest::get(url).await?;
70    response.json().await.map_err(Error::from)
71}
72
73async fn read_json_from_path<T>(path: impl AsRef<Path>) -> Result<T>
74where
75    T: DeserializeOwned,
76{
77    let string = tokio::fs::read_to_string(path).await?;
78    serde_json::from_str(&string).map_err(Error::from)
79}
80
81#[cfg(test)]
82mod tests {
83    use stac::{Href, Item};
84
85    #[tokio::test]
86    async fn read_filesystem() {
87        let item: Item = super::read("examples/simple-item.json").await.unwrap();
88        assert!(item.href().unwrap().ends_with("examples/simple-item.json"));
89    }
90
91    #[tokio::test]
92    async fn read_network() {
93        let href = "https://raw.githubusercontent.com/radiantearth/stac-spec/v1.0.0/examples/simple-item.json";
94        let item: Item = super::read(href).await.unwrap();
95        assert_eq!(item.href().unwrap(), href);
96    }
97}