google_cloud_storage/model_ext/
open_object_request.rs

1// Copyright 2025 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::{
16    google::storage::v2::BidiReadObjectSpec, model::CommonObjectRequestParams, model_ext::ReadRange,
17};
18use gaxi::prost::ToProto;
19
20/// The request type for a bidi read object streaming RPC.
21///
22/// This type is used in the Storage [stub][crate::stub::Storage] to represent
23/// a request for [open_object][crate::client::Storage::open_object].
24/// Applications rarely use this type directly, but it might be used in tests
25/// where the client library is being mocked.
26// Implementation note: this type exclude some fields from the proto, such as
27// the read handle and routing token, as these cannot be set by the application.
28#[derive(Clone, Debug, Default, PartialEq)]
29#[non_exhaustive]
30pub struct OpenObjectRequest {
31    /// The bucket containing the target object.
32    pub bucket: String,
33    /// The target object name.
34    pub object: String,
35    /// The target object generation. If zero, then target the latest version of the object.
36    pub generation: i64,
37    /// If set, return an error if the current generation does not match the value.
38    pub if_generation_match: Option<i64>,
39    /// If set, return an error if the current generation matches the value.
40    pub if_generation_not_match: Option<i64>,
41    /// If set, return an error if the current metageneration does not match the value.
42    pub if_metageneration_match: Option<i64>,
43    /// If set, return an error if the current metageneration matches the value.
44    pub if_metageneration_not_match: Option<i64>,
45    /// Parameters that can be passed to any object request.
46    ///
47    /// At the moment, these are only encryption parameters for
48    /// [Customer-Supplied Encryption Keys].
49    ///
50    /// [Customer-Supplied Encryption Keys]: https://docs.cloud.google.com/storage/docs/encryption/customer-supplied-keys
51    pub common_object_request_params: Option<CommonObjectRequestParams>,
52
53    /// The list of ranges to read as part of the initial request.
54    ///
55    /// Applications can open an object and issue a read request in the same RPC
56    /// using [OpenObject::send_and_read][crate::builder::storage::OpenObject::send_and_read].
57    ///
58    /// In the future, we may offer methods to issue more than one read request.
59    pub ranges: Vec<ReadRange>,
60}
61
62impl OpenObjectRequest {
63    /// Sets the [bucket][OpenObjectRequest::bucket] field.
64    pub fn set_bucket<T>(mut self, v: T) -> Self
65    where
66        T: Into<String>,
67    {
68        self.bucket = v.into();
69        self
70    }
71
72    /// Sets the [object][OpenObjectRequest::object] field.
73    pub fn set_object<T>(mut self, v: T) -> Self
74    where
75        T: Into<String>,
76    {
77        self.object = v.into();
78        self
79    }
80
81    /// Sets the [generation][OpenObjectRequest::generation] field.
82    pub fn set_generation(mut self, v: i64) -> Self {
83        self.generation = v;
84        self
85    }
86
87    /// Sets the [if_generation_match][OpenObjectRequest::if_generation_match] field.
88    pub fn set_if_generation_match(mut self, v: i64) -> Self {
89        self.if_generation_match = Some(v);
90        self
91    }
92
93    /// Sets the [if_generation_match][OpenObjectRequest::if_generation_match] field.
94    pub fn set_or_clear_if_generation_match(mut self, v: Option<i64>) -> Self {
95        self.if_generation_match = v;
96        self
97    }
98
99    /// Sets the [if_generation_not_match][OpenObjectRequest::if_generation_not_match] field.
100    pub fn set_if_generation_not_match(mut self, v: i64) -> Self {
101        self.if_generation_not_match = Some(v);
102        self
103    }
104
105    /// Sets the [if_generation_not_match][OpenObjectRequest::if_generation_not_match] field.
106    pub fn set_or_clear_if_generation_not_match(mut self, v: Option<i64>) -> Self {
107        self.if_generation_not_match = v;
108        self
109    }
110
111    /// Sets the [if_metageneration_match][OpenObjectRequest::if_metageneration_match] field.
112    pub fn set_if_metageneration_match(mut self, v: i64) -> Self {
113        self.if_metageneration_match = Some(v);
114        self
115    }
116
117    /// Sets the [if_metageneration_match][OpenObjectRequest::if_metageneration_match] field.
118    pub fn set_or_clear_if_metageneration_match(mut self, v: Option<i64>) -> Self {
119        self.if_metageneration_match = v;
120        self
121    }
122
123    /// Sets the [if_metageneration_not_match][OpenObjectRequest::if_metageneration_not_match] field.
124    pub fn set_if_metageneration_not_match(mut self, v: i64) -> Self {
125        self.if_metageneration_not_match = Some(v);
126        self
127    }
128
129    /// Sets the [if_metageneration_not_match][OpenObjectRequest::if_metageneration_not_match] field.
130    pub fn set_or_clear_if_metageneration_not_match(mut self, v: Option<i64>) -> Self {
131        self.if_metageneration_not_match = v;
132        self
133    }
134
135    /// Sets the [common_object_request_params][OpenObjectRequest::common_object_request_params] field.
136    pub fn set_common_object_request_params(mut self, v: CommonObjectRequestParams) -> Self {
137        self.common_object_request_params = Some(v);
138        self
139    }
140
141    /// Sets the [common_object_request_params][OpenObjectRequest::common_object_request_params] field.
142    pub fn set_or_clear_common_object_request_params(
143        mut self,
144        v: Option<CommonObjectRequestParams>,
145    ) -> Self {
146        self.common_object_request_params = v;
147        self
148    }
149
150    pub(crate) fn into_parts(mut self) -> (BidiReadObjectSpec, Vec<ReadRange>) {
151        let ranges = std::mem::take(&mut self.ranges);
152        (BidiReadObjectSpec::from(self), ranges)
153    }
154}
155
156impl From<OpenObjectRequest> for BidiReadObjectSpec {
157    fn from(value: OpenObjectRequest) -> Self {
158        let proto = value
159            .common_object_request_params
160            .map(ToProto::to_proto)
161            .transpose()
162            .expect("CommonObjectRequestParams to proto never fails");
163        Self {
164            bucket: value.bucket,
165            object: value.object,
166            generation: value.generation,
167            if_generation_match: value.if_generation_match,
168            if_generation_not_match: value.if_generation_not_match,
169            if_metageneration_match: value.if_metageneration_match,
170            if_metageneration_not_match: value.if_metageneration_not_match,
171            common_object_request_params: proto,
172            ..BidiReadObjectSpec::default()
173        }
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::*;
180    use crate::google::storage::v2::CommonObjectRequestParams as ProtoParams;
181    use pastey::paste;
182
183    #[test]
184    fn bucket() {
185        let got = OpenObjectRequest::default().set_bucket("bucket");
186        assert_eq!(got.bucket, "bucket");
187        let got = got.set_bucket("");
188        assert_eq!(got, OpenObjectRequest::default());
189    }
190
191    #[test]
192    fn object() {
193        let got = OpenObjectRequest::default().set_object("object");
194        assert_eq!(got.object, "object");
195        let got = got.set_object("");
196        assert_eq!(got, OpenObjectRequest::default());
197    }
198
199    #[test]
200    fn generation() {
201        let got = OpenObjectRequest::default().set_generation(42);
202        assert_eq!(got.generation, 42);
203        let got = got.set_generation(0);
204        assert_eq!(got, OpenObjectRequest::default());
205    }
206
207    macro_rules! setter {
208        ($field:ident) => {
209            paste! {
210                #[test]
211                fn $field() {
212                    let got = OpenObjectRequest::default().[<set_$field>](42);
213                    assert_eq!(got.$field, Some(42));
214                    let got = got.[<set_or_clear_$field>](Some(7));
215                    assert_eq!(got.$field, Some(7));
216                    let got = got.[<set_or_clear_$field>](None);
217                    assert_eq!(got.$field, None);
218                    assert_eq!(got, OpenObjectRequest::default());
219                }
220            }
221        };
222    }
223
224    setter!(if_generation_match);
225    setter!(if_generation_not_match);
226    setter!(if_metageneration_match);
227    setter!(if_metageneration_not_match);
228
229    #[test]
230    fn common_object_request_params() {
231        let got = OpenObjectRequest::default().set_common_object_request_params(
232            CommonObjectRequestParams::new().set_encryption_algorithm("abc"),
233        );
234        assert_eq!(
235            got.common_object_request_params,
236            Some(CommonObjectRequestParams::new().set_encryption_algorithm("abc"))
237        );
238        let got = got.set_or_clear_common_object_request_params(None);
239        assert_eq!(got, OpenObjectRequest::default());
240    }
241
242    #[test]
243    fn from() {
244        let got = BidiReadObjectSpec::from(
245            OpenObjectRequest::default()
246                .set_bucket("bucket")
247                .set_object("object")
248                .set_generation(123)
249                .set_if_generation_match(234)
250                .set_if_generation_not_match(345)
251                .set_if_metageneration_match(456)
252                .set_if_metageneration_not_match(567)
253                .set_common_object_request_params(
254                    CommonObjectRequestParams::new().set_encryption_algorithm("test-abc"),
255                ),
256        );
257        let want = BidiReadObjectSpec {
258            bucket: "bucket".into(),
259            object: "object".into(),
260            generation: 123,
261            if_generation_match: Some(234),
262            if_generation_not_match: Some(345),
263            if_metageneration_match: Some(456),
264            if_metageneration_not_match: Some(567),
265            common_object_request_params: Some(ProtoParams {
266                encryption_algorithm: "test-abc".into(),
267                ..ProtoParams::default()
268            }),
269            ..BidiReadObjectSpec::default()
270        };
271        assert_eq!(got, want);
272    }
273}