1use crate::common::StorageClass;
4use http::uri::Authority;
5use std::collections::BTreeMap;
6
7#[doc(hidden)]
8#[macro_export]
9macro_rules! __make_obj_url {
10 ($url:expr, $authority:expr, $id:expr) => {{
11 format!(
12 $url,
13 $authority.as_str(),
14 percent_encoding::percent_encode($id.bucket().as_ref(), $crate::util::PATH_ENCODE_SET),
15 percent_encoding::percent_encode($id.object().as_ref(), $crate::util::PATH_ENCODE_SET)
16 )
17 }};
18}
19
20mod delete;
21mod download;
22mod get;
23mod insert;
24mod list;
25mod patch;
26mod rewrite;
27
28pub use delete::*;
29pub use download::*;
30pub use get::*;
31pub use insert::*;
32pub use list::*;
33pub use patch::*;
34pub use rewrite::*;
35
36pub type Timestamp = time::OffsetDateTime;
37
38#[derive(Clone, Debug)]
42pub struct Object {
43 authority: Authority,
44}
45
46impl Object {
47 pub fn with_authority(authority: Authority) -> Self {
50 Self { authority }
51 }
52}
53
54impl Default for Object {
55 fn default() -> Self {
57 Self {
58 authority: Authority::from_static("storage.googleapis.com"),
59 }
60 }
61}
62
63#[derive(Default, Serialize, Deserialize)]
66#[serde(rename_all = "camelCase")]
67pub struct Metadata {
68 #[serde(skip_serializing)]
70 pub id: Option<String>,
71 #[serde(skip_serializing)]
73 pub self_link: Option<String>,
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub name: Option<String>,
77 #[serde(skip_serializing)]
79 pub bucket: Option<String>,
80 #[serde(default, skip_serializing, deserialize_with = "from_str_opt")]
82 pub generation: Option<i64>,
83 #[serde(default, skip_serializing, deserialize_with = "from_str_opt")]
88 pub metageneration: Option<i64>,
89 #[serde(skip_serializing_if = "Option::is_none")]
92 pub content_type: Option<String>,
93 #[serde(skip_serializing_if = "Option::is_none")]
95 pub content_disposition: Option<String>,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub content_encoding: Option<String>,
99 #[serde(default, skip_serializing, deserialize_with = "timestamp_rfc3339_opt")]
101 pub time_created: Option<Timestamp>,
102 #[serde(default, skip_serializing, deserialize_with = "timestamp_rfc3339_opt")]
104 pub updated: Option<Timestamp>,
105 #[serde(skip_serializing_if = "Option::is_none")]
107 pub storage_class: Option<StorageClass>,
108 #[serde(default, skip_serializing, deserialize_with = "timestamp_rfc3339_opt")]
111 pub time_storage_class_updated: Option<Timestamp>,
112 #[serde(default, skip_serializing, deserialize_with = "from_str_opt")]
114 pub size: Option<u64>,
115 #[serde(skip_serializing_if = "Option::is_none")]
118 pub md5_hash: Option<String>,
119 #[serde(skip_serializing)]
121 pub media_link: Option<String>,
122 #[serde(skip_serializing_if = "Option::is_none")]
124 pub content_language: Option<String>,
125 #[serde(skip_serializing_if = "Option::is_none")]
129 pub crc32c: Option<String>,
130 #[serde(skip_serializing)]
132 pub etag: Option<String>,
133 #[serde(skip_serializing_if = "Option::is_none")]
135 pub metadata: Option<BTreeMap<String, String>>,
136}
137
138use serde::de::Deserialize;
139
140fn from_str_opt<'de, T, D>(deserializer: D) -> Result<Option<T>, D::Error>
141where
142 T: std::str::FromStr,
143 T::Err: std::fmt::Display,
144 D: serde::de::Deserializer<'de>,
145{
146 let s: &str = Deserialize::deserialize(deserializer)?;
147 T::from_str(s).map_err(serde::de::Error::custom).map(Some)
148}
149
150fn from_str<'de, T, D>(deserializer: D) -> Result<T, D::Error>
151where
152 T: std::str::FromStr,
153 T::Err: std::fmt::Display,
154 D: serde::de::Deserializer<'de>,
155{
156 let s: &str = Deserialize::deserialize(deserializer)?;
157 T::from_str(s).map_err(serde::de::Error::custom)
158}
159
160fn timestamp_rfc3339_opt<'de, D>(deserializer: D) -> Result<Option<Timestamp>, D::Error>
161where
162 D: serde::de::Deserializer<'de>,
163{
164 let ts_str: &str = Deserialize::deserialize(deserializer)?;
165 Timestamp::parse(ts_str, &time::format_description::well_known::Rfc3339)
166 .map_err(serde::de::Error::custom)
167 .map(Some)
168}