Skip to main content

fuchsia_repo/
resource.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::range::ContentRange;
6use crate::repository::Error;
7use crate::util::read_stream_to_end;
8use bytes::Bytes;
9use fidl_fuchsia_pkg_ext::RepositoryConfig;
10use futures::future::ready;
11use futures::stream::once;
12use std::io;
13use std::pin::Pin;
14
15/// [Resource] represents some resource as a stream of [Bytes] as provided from
16/// a repository server.
17pub struct Resource {
18    /// The range in bytes available for this resource.
19    pub content_range: ContentRange,
20
21    /// A stream of bytes representing the resource.
22    pub stream:
23        Pin<Box<dyn futures::stream::Stream<Item = io::Result<Bytes>> + Send + Sync + 'static>>,
24}
25
26impl Resource {
27    /// The length of the content in bytes in the stream. This may be smaller than the total length
28    /// of the file.
29    pub fn content_len(&self) -> u64 {
30        self.content_range.content_len()
31    }
32
33    /// The total length of the file range in bytes. This may be larger than the bytes in the stream.
34    pub fn total_len(&self) -> u64 {
35        self.content_range.total_len()
36    }
37
38    pub async fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<(), Error> {
39        buf.reserve(self.content_len() as usize);
40        read_stream_to_end(&mut self.stream, buf).await.map_err(Error::Io)
41    }
42}
43
44impl std::fmt::Debug for Resource {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        f.debug_struct("resource")
47            .field("content_range", &self.content_range)
48            .field("stream", &"..")
49            .finish()
50    }
51}
52
53impl TryFrom<RepositoryConfig> for Resource {
54    type Error = Error;
55
56    fn try_from(config: RepositoryConfig) -> Result<Resource, Error> {
57        let json = Bytes::from(serde_json::to_vec(&config).map_err(|e| anyhow::anyhow!(e))?);
58        let complete_len = json.len() as u64;
59        Ok(Resource {
60            content_range: ContentRange::Full { complete_len },
61            stream: Box::pin(once(ready(Ok(json)))),
62        })
63    }
64}