diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6411b4fb..823e78cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@v4 - uses: Swatinem/rust-cache@v2 - name: Test - run: cargo test -p stac -p stac-types --all-features + run: cargo test -p stac --all-features check-features-core: name: Check stac features runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 74b3a45a..6743df5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ members = [ "crates/extensions", "crates/pgstac", "crates/server", - "crates/types", ] default-members = [ "crates/api", @@ -17,7 +16,6 @@ default-members = [ "crates/core", "crates/derive", "crates/extensions", - "crates/types", ] [workspace.package] @@ -77,7 +75,6 @@ stac-api = { version = "0.6.2", path = "crates/api" } stac-derive = { version = "0.1.0", path = "crates/derive" } stac-duckdb = { version = "0.0.3", path = "crates/duckdb" } stac-server = { version = "0.3.2", path = "crates/server" } -stac-types = { version = "0.1.0", path = "crates/types" } syn = "2.0" tempfile = "3.13" thiserror = "2.0" diff --git a/crates/api/Cargo.toml b/crates/api/Cargo.toml index a7e2b7e4..09ca597a 100644 --- a/crates/api/Cargo.toml +++ b/crates/api/Cargo.toml @@ -18,7 +18,6 @@ client = [ "dep:http", "dep:reqwest", "dep:tokio", - "stac-types/reqwest", ] geo = ["dep:geo", "stac/geo"] python = ["dep:pyo3", "dep:pythonize"] @@ -37,7 +36,6 @@ serde_json.workspace = true serde_urlencoded.workspace = true stac.workspace = true stac-derive.workspace = true -stac-types.workspace = true pyo3 = { workspace = true, optional = true } pythonize = { workspace = true, optional = true } thiserror.workspace = true diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 26d493b6..05eb35e5 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -39,7 +39,6 @@ stac = { workspace = true, features = [ stac-api = { workspace = true, features = ["client"] } stac-duckdb = { workspace = true, optional = true } stac-server = { workspace = true, features = ["axum"] } -stac-types.workspace = true thiserror.workspace = true tokio = { workspace = true, features = [ "macros", diff --git a/crates/cli/src/error.rs b/crates/cli/src/error.rs index 4ed18a19..f814c1f7 100644 --- a/crates/cli/src/error.rs +++ b/crates/cli/src/error.rs @@ -42,10 +42,6 @@ pub enum Error { #[error(transparent)] StacServer(#[from] stac_server::Error), - /// [stac_types::Error] - #[error(transparent)] - StacTypes(#[from] stac_types::Error), - /// [tokio::sync::mpsc::error::SendError] #[error(transparent)] TokioSend(#[from] tokio::sync::mpsc::error::SendError), diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index faa3bc9b..acf643bb 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -42,7 +42,7 @@ object-store-all = [ "object-store-gcp", "object-store-http", ] -reqwest = ["dep:reqwest", "stac-types/reqwest"] +reqwest = ["dep:reqwest"] reqwest-rustls = ["reqwest/rustls-tls"] validate = ["dep:jsonschema", "dep:reqwest", "dep:tokio", "dep:fluent-uri"] validate-blocking = ["validate", "tokio/rt"] @@ -61,17 +61,17 @@ geoarrow = { workspace = true, optional = true } geojson.workspace = true jsonschema = { workspace = true, optional = true } log.workspace = true +mime.workspace = true object_store = { workspace = true, optional = true } parquet = { workspace = true, optional = true } reqwest = { workspace = true, features = ["json", "blocking"], optional = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true, features = ["preserve_order"] } stac-derive.workspace = true -stac-types.workspace = true thiserror.workspace = true tokio = { workspace = true, optional = true } tracing.workspace = true -url.workspace = true +url = { workspace = true, features = ["serde"] } [dev-dependencies] assert-json-diff.workspace = true diff --git a/crates/core/src/error.rs b/crates/core/src/error.rs index 6ea40311..e597618f 100644 --- a/crates/core/src/error.rs +++ b/crates/core/src/error.rs @@ -1,3 +1,4 @@ +use crate::Version; use thiserror::Error; /// Error enum for crate-specific errors. @@ -46,6 +47,16 @@ pub enum Error { #[error(transparent)] Io(#[from] std::io::Error), + /// Returned when a STAC object has the wrong type field. + #[error("incorrect type: expected={expected}, actual={actual}")] + IncorrectType { + /// The actual type field on the object. + actual: String, + + /// The expected value. + expected: String, + }, + /// Returned when a property name conflicts with a top-level STAC field, or /// it's an invalid top-level field name. #[error("invalid attribute name: {0}")] @@ -67,6 +78,14 @@ pub enum Error { #[error("no items")] NoItems, + /// There is not an href, when an href is required. + #[error("no href")] + NoHref, + + /// This is not a JSON object. + #[error("json value is not an object")] + NotAnObject(serde_json::Value), + /// [object_store::Error] #[error(transparent)] #[cfg(feature = "object-store")] @@ -95,10 +114,6 @@ pub enum Error { #[error(transparent)] SerdeJson(#[from] serde_json::Error), - /// [stac_types::Error] - #[error(transparent)] - StacTypes(#[from] stac_types::Error), - /// [tokio::task::JoinError] #[error(transparent)] #[cfg(any(feature = "validate", feature = "object-store"))] @@ -120,6 +135,10 @@ pub enum Error { #[error("unsupported geoparquet type")] UnsupportedGeoparquetType, + /// Unsupported migration. + #[error("unsupported migration: {0} to {1}")] + UnsupportedMigration(Version, Version), + /// [url::ParseError] #[error(transparent)] UrlParse(#[from] url::ParseError), diff --git a/crates/types/src/fields.rs b/crates/core/src/fields.rs similarity index 100% rename from crates/types/src/fields.rs rename to crates/core/src/fields.rs diff --git a/crates/core/src/format.rs b/crates/core/src/format.rs index 040e527d..9c3ff4b8 100644 --- a/crates/core/src/format.rs +++ b/crates/core/src/format.rs @@ -1,9 +1,8 @@ use crate::{ geoparquet::{Compression, FromGeoparquet, IntoGeoparquet}, - Error, FromJson, FromNdjson, Href, Result, SelfHref, ToJson, ToNdjson, + Error, FromJson, FromNdjson, Href, RealizedHref, Result, SelfHref, ToJson, ToNdjson, }; use bytes::Bytes; -use stac_types::RealizedHref; use std::{fmt::Display, path::Path, str::FromStr}; /// The format of STAC data. diff --git a/crates/types/src/href.rs b/crates/core/src/href.rs similarity index 98% rename from crates/types/src/href.rs rename to crates/core/src/href.rs index 469027b6..f00424f2 100644 --- a/crates/types/src/href.rs +++ b/crates/core/src/href.rs @@ -21,6 +21,7 @@ pub enum Href { String(String), } +/// An href that has been realized to a path or a url. #[derive(Debug)] pub enum RealizedHref { /// A path buf @@ -225,8 +226,8 @@ impl TryFrom for Url { } #[cfg(feature = "reqwest")] -impl From for Href { - fn from(value: reqwest::Url) -> Self { +impl From for Href { + fn from(value: Url) -> Self { Href::Url(value) } } diff --git a/crates/core/src/item_collection.rs b/crates/core/src/item_collection.rs index 2f682857..b4177247 100644 --- a/crates/core/src/item_collection.rs +++ b/crates/core/src/item_collection.rs @@ -1,4 +1,4 @@ -use crate::{Error, Href, Item, Link, Migrate, Version}; +use crate::{Error, Href, Item, Link, Migrate, Result, Version}; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; use stac_derive::{Links, SelfHref}; @@ -61,7 +61,7 @@ impl Deref for ItemCollection { } impl Migrate for ItemCollection { - fn migrate(mut self, version: &Version) -> stac_types::Result { + fn migrate(mut self, version: &Version) -> Result { let mut items = Vec::with_capacity(self.items.len()); for item in self.items { items.push(item.migrate(version)?); @@ -74,7 +74,7 @@ impl Migrate for ItemCollection { impl TryFrom for ItemCollection { type Error = Error; - fn try_from(value: Value) -> Result { + fn try_from(value: Value) -> Result { match serde_json::from_value::(value.clone()) { Ok(item_collection) => Ok(item_collection), Err(err) => { diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 719bb7a9..6bea547d 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -147,6 +147,10 @@ unused_results )] +// Enables derive macros here and elsewhere. +// https://users.rust-lang.org/t/use-of-imported-types-in-derive-macro/94676/3 +extern crate self as stac; + mod asset; mod band; mod bbox; @@ -155,17 +159,22 @@ mod collection; mod data_type; pub mod datetime; mod error; +mod fields; mod format; #[cfg(feature = "geo")] pub mod geo; #[cfg(feature = "geoarrow")] pub mod geoarrow; pub mod geoparquet; +mod href; pub mod io; pub mod item; mod item_asset; mod item_collection; mod json; +pub mod link; +mod migrate; +pub mod mime; mod ndjson; mod node; #[cfg(feature = "object-store")] @@ -174,12 +183,12 @@ mod statistics; #[cfg(feature = "validate")] mod validate; mod value; +mod version; use std::fmt::Display; #[cfg(feature = "object-store")] pub use resolver::Resolver; -pub use stac_types::{mime, Fields, Href, Link, Links, Migrate, SelfHref, Version, STAC_VERSION}; #[cfg(feature = "validate-blocking")] pub use validate::ValidateBlocking; #[cfg(feature = "validate")] @@ -192,19 +201,27 @@ pub use { collection::{Collection, Extent, Provider, SpatialExtent, TemporalExtent}, data_type::DataType, error::Error, + fields::Fields, format::Format, geoparquet::{FromGeoparquet, IntoGeoparquet}, + href::{Href, RealizedHref, SelfHref}, io::{read, write}, item::{FlatItem, Item, Properties}, item_asset::ItemAsset, item_collection::ItemCollection, json::{FromJson, ToJson}, + link::{Link, Links}, + migrate::Migrate, ndjson::{FromNdjson, ToNdjson}, node::{Container, Node}, statistics::Statistics, value::Value, + version::Version, }; +/// The default STAC version of this library. +pub const STAC_VERSION: Version = Version::v1_1_0; + /// Custom [Result](std::result::Result) type for this crate. pub type Result = std::result::Result; diff --git a/crates/types/src/link.rs b/crates/core/src/link.rs similarity index 99% rename from crates/types/src/link.rs rename to crates/core/src/link.rs index 35b2700f..b84aea84 100644 --- a/crates/types/src/link.rs +++ b/crates/core/src/link.rs @@ -711,7 +711,7 @@ mod tests { } mod links { - use stac::{Catalog, Item, Link, Links}; + use crate::{Catalog, Item, Link, Links}; #[test] fn link() { diff --git a/crates/types/src/migrate.rs b/crates/core/src/migrate.rs similarity index 95% rename from crates/types/src/migrate.rs rename to crates/core/src/migrate.rs index a44a8db1..35f61e57 100644 --- a/crates/types/src/migrate.rs +++ b/crates/core/src/migrate.rs @@ -225,13 +225,13 @@ fn migrate_license(object: &mut Map) { #[cfg(test)] mod tests { + use crate::{Collection, DataType, Item, Link, Links, Migrate, Version}; use assert_json_diff::assert_json_eq; use serde_json::Value; - use stac::{Collection, DataType, Item, Link, Links, Migrate, Version}; #[test] fn migrate_v1_0_0_to_v1_1_0() { - let item: Item = stac::read("data/bands-v1.0.0.json").unwrap(); + let item: Item = crate::read("data/bands-v1.0.0.json").unwrap(); let item = item.migrate(&Version::v1_1_0).unwrap(); let asset = &item.assets["example"]; assert_eq!(asset.data_type.as_ref().unwrap(), &DataType::UInt16); @@ -241,7 +241,7 @@ mod tests { assert_eq!(asset.bands[3].name.as_ref().unwrap(), "nir"); let expected: Value = - serde_json::to_value(stac::read::("data/bands-v1.1.0.json").unwrap()).unwrap(); + serde_json::to_value(crate::read::("data/bands-v1.1.0.json").unwrap()).unwrap(); assert_json_eq!(expected, serde_json::to_value(item).unwrap()); let mut collection = Collection::new("an-id", "a description"); @@ -259,7 +259,7 @@ mod tests { #[test] fn remove_empty_bands() { // https://github.com/stac-utils/stac-rs/issues/350 - let item: Item = stac::read("data/20201211_223832_CS2.json").unwrap(); + let item: Item = crate::read("data/20201211_223832_CS2.json").unwrap(); let item = item.migrate(&Version::v1_1_0).unwrap(); let asset = &item.assets["data"]; assert!(asset.bands.is_empty()); @@ -267,7 +267,7 @@ mod tests { #[test] fn migrate_v1_1_0_to_v1_1_0() { - let item: Item = stac::read("../../spec-examples/v1.1.0/simple-item.json").unwrap(); + let item: Item = crate::read("../../spec-examples/v1.1.0/simple-item.json").unwrap(); let _ = item.migrate(&Version::v1_1_0).unwrap(); } } diff --git a/crates/types/src/mime.rs b/crates/core/src/mime.rs similarity index 100% rename from crates/types/src/mime.rs rename to crates/core/src/mime.rs diff --git a/crates/core/src/ndjson.rs b/crates/core/src/ndjson.rs index c3874bdf..11c902a9 100644 --- a/crates/core/src/ndjson.rs +++ b/crates/core/src/ndjson.rs @@ -1,7 +1,6 @@ -use crate::{Error, FromJson, Item, ItemCollection, Result, Value}; +use crate::{Error, FromJson, Item, ItemCollection, Result, SelfHref, Value}; use bytes::Bytes; use serde::Serialize; -use stac_types::SelfHref; use std::{ fs::File, io::{BufRead, BufReader, BufWriter, Write}, diff --git a/crates/core/src/node.rs b/crates/core/src/node.rs index 9a3fdada..1271ed8f 100644 --- a/crates/core/src/node.rs +++ b/crates/core/src/node.rs @@ -137,7 +137,7 @@ impl TryFrom for Container { match value { Value::Catalog(c) => Ok(c.into()), Value::Collection(c) => Ok(c.into()), - _ => Err(stac_types::Error::IncorrectType { + _ => Err(Error::IncorrectType { actual: value.type_name().to_string(), expected: "Catalog or Collection".to_string(), } diff --git a/crates/core/src/value.rs b/crates/core/src/value.rs index 799e24d8..e0b71ee2 100644 --- a/crates/core/src/value.rs +++ b/crates/core/src/value.rs @@ -1,9 +1,9 @@ use crate::{ - Catalog, Collection, Error, Href, Item, ItemCollection, Link, Links, Migrate, Result, Version, + Catalog, Collection, Error, Href, Item, ItemCollection, Link, Links, Migrate, Result, SelfHref, + Version, }; use serde::{Deserialize, Serialize}; use serde_json::Map; -use stac_types::SelfHref; use std::convert::TryFrom; /// An enum that can hold any STAC object type. @@ -260,7 +260,7 @@ macro_rules! impl_try_from { if let Value::$object(o) = value { Ok(o) } else { - Err(stac_types::Error::IncorrectType { + Err(Error::IncorrectType { actual: value.type_name().to_string(), expected: $name.to_string(), } @@ -284,7 +284,7 @@ impl TryFrom for ItemCollection { match value { Value::Item(item) => Ok(ItemCollection::from(vec![item])), Value::ItemCollection(item_collection) => Ok(item_collection), - Value::Catalog(_) | Value::Collection(_) => Err(stac_types::Error::IncorrectType { + Value::Catalog(_) | Value::Collection(_) => Err(Error::IncorrectType { actual: value.type_name().to_string(), expected: "ItemCollection".to_string(), } @@ -294,7 +294,7 @@ impl TryFrom for ItemCollection { } impl Migrate for Value { - fn migrate(self, version: &Version) -> stac_types::Result { + fn migrate(self, version: &Version) -> Result { match self { Value::Item(item) => item.migrate(version).map(Value::Item), Value::Catalog(catalog) => catalog.migrate(version).map(Value::Catalog), diff --git a/crates/types/src/version.rs b/crates/core/src/version.rs similarity index 100% rename from crates/types/src/version.rs rename to crates/core/src/version.rs diff --git a/crates/derive/src/lib.rs b/crates/derive/src/lib.rs index c6a86a46..bc005a63 100644 --- a/crates/derive/src/lib.rs +++ b/crates/derive/src/lib.rs @@ -7,11 +7,11 @@ pub fn self_href_derive(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let expanded = quote! { - impl stac_types::SelfHref for #name { - fn self_href(&self) -> Option<&stac_types::Href> { + impl ::stac::SelfHref for #name { + fn self_href(&self) -> Option<&::stac::Href> { self.self_href.as_ref() } - fn self_href_mut(&mut self) -> &mut Option { + fn self_href_mut(&mut self) -> &mut Option<::stac::Href> { &mut self.self_href } } @@ -24,11 +24,11 @@ pub fn links_derive(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let expanded = quote! { - impl stac_types::Links for #name { - fn links(&self) -> &[stac_types::Link] { + impl ::stac::Links for #name { + fn links(&self) -> &[::stac::Link] { &self.links } - fn links_mut(&mut self) -> &mut Vec { + fn links_mut(&mut self) -> &mut Vec<::stac::Link> { &mut self.links } } @@ -41,7 +41,7 @@ pub fn migrate_derive(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let expanded = quote! { - impl stac_types::Migrate for #name {} + impl ::stac::Migrate for #name {} }; TokenStream::from(expanded) } @@ -51,7 +51,7 @@ pub fn fields_derive(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as DeriveInput); let name = input.ident; let expanded = quote! { - impl stac_types::Fields for #name { + impl ::stac::Fields for #name { fn fields(&self) -> &serde_json::Map { &self.additional_fields } diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index edc76591..5428324f 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -28,7 +28,6 @@ serde_json.workspace = true serde_urlencoded.workspace = true stac.workspace = true stac-api = { workspace = true, features = ["geo"] } -stac-types.workspace = true thiserror.workspace = true tokio-postgres = { workspace = true, optional = true } tower-http = { workspace = true, features = ["cors", "trace"], optional = true } diff --git a/crates/server/src/error.rs b/crates/server/src/error.rs index f665db13..b3197619 100644 --- a/crates/server/src/error.rs +++ b/crates/server/src/error.rs @@ -37,10 +37,6 @@ pub enum Error { #[error(transparent)] StacApi(#[from] stac_api::Error), - /// [stac_types::Error] - #[error(transparent)] - StacTypes(#[from] stac_types::Error), - /// [tokio_postgres::Error] #[cfg(feature = "pgstac")] #[error(transparent)] diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml deleted file mode 100644 index 7a23cc9b..00000000 --- a/crates/types/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "stac-types" -description = "Low-level types for stac-rs. Should not be used directly, usually." -version = "0.1.0" -authors.workspace = true -edition.workspace = true -homepage.workspace = true -repository.workspace = true -license.workspace = true -categories.workspace = true -rust-version.workspace = true - -[features] -reqwest = ["dep:reqwest"] - -[dependencies] -mime.workspace = true -reqwest = { workspace = true, optional = true } -serde = { workspace = true, features = ["derive"] } -serde_json.workspace = true -thiserror.workspace = true -url = { workspace = true, features = ["serde"] } -tracing.workspace = true -stac-derive.workspace = true - -[dev-dependencies] -assert-json-diff.workspace = true -stac.workspace = true diff --git a/crates/types/data b/crates/types/data deleted file mode 120000 index 0a1953bd..00000000 --- a/crates/types/data +++ /dev/null @@ -1 +0,0 @@ -../core/data \ No newline at end of file diff --git a/crates/types/examples b/crates/types/examples deleted file mode 120000 index 2419d7c4..00000000 --- a/crates/types/examples +++ /dev/null @@ -1 +0,0 @@ -../../spec-examples/v1.1.0 \ No newline at end of file diff --git a/crates/types/src/error.rs b/crates/types/src/error.rs deleted file mode 100644 index 0a3b2582..00000000 --- a/crates/types/src/error.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::Version; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum Error { - /// Returned when a STAC object has the wrong type field. - #[error("incorrect type: expected={expected}, actual={actual}")] - IncorrectType { - /// The actual type field on the object. - actual: String, - - /// The expected value. - expected: String, - }, - - /// [std::io::Error] - #[error(transparent)] - Io(#[from] std::io::Error), - - /// There is not an href, when an href is required. - #[error("no href")] - NoHref, - - /// This is not a JSON object. - #[error("json value is not an object")] - NotAnObject(serde_json::Value), - - /// [serde_json::Error] - #[error(transparent)] - SerdeJson(#[from] serde_json::Error), - - /// Unsupported migration. - #[error("unsupported migration: {0} to {1}")] - UnsupportedMigration(Version, Version), - - /// [url::ParseError] - #[error(transparent)] - UrlParse(#[from] url::ParseError), -} diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs deleted file mode 100644 index f670c4cd..00000000 --- a/crates/types/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -mod error; -mod fields; -mod href; -pub mod link; -mod migrate; -pub mod mime; -mod version; - -pub type Result = std::result::Result; - -pub use { - error::Error, - fields::Fields, - href::{Href, RealizedHref, SelfHref}, - link::{Link, Links}, - migrate::Migrate, - version::Version, -}; - -/// The default STAC version of this library. -pub const STAC_VERSION: Version = Version::v1_1_0; -extern crate self as stac_types;