Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 224af64

Browse files
committed
feat(doit):optimized memory allocation and options
* reserve_exact(X) where possible (params, multi-part-reader) * `if let` used whereever possible to prevent duplicate checks This increases the possible performance, and makes for more readable, concise code.
1 parent e53e23a commit 224af64

5 files changed

Lines changed: 1079 additions & 956 deletions

File tree

gen/youtube3/cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,3 @@ mime = "*"
1919
url = "*"
2020
rustc-serialize = "*"
2121
yup-oauth2 = "*"
22-
23-
[dev-dependencies]
24-
yup-hyper-mock = "*"

gen/youtube3/src/cmn.rs

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
// COPY OF 'src/rust/cmn.rs'
22
// DO NOT EDIT
33
use std::marker::MarkerTrait;
4-
use std::io::{self, Read, Seek, Cursor};
4+
use std::io::{self, Read, Seek, Cursor, Write, SeekFrom};
5+
use std::default::Default;
56

6-
use mime;
7+
use mime::{Mime, TopLevel, SubLevel, Attr, Value};
78
use oauth2;
89
use hyper;
10+
use hyper::header::{ContentType, ContentLength, Headers};
11+
use hyper::http::LINE_ENDING;
912

1013
/// Identifies the Hub. There is only one per library, this trait is supposed
1114
/// to make intended use more explicit.
@@ -119,19 +122,26 @@ pub enum Result<T = ()> {
119122
Success(T),
120123
}
121124

125+
const BOUNDARY: &'static str = "MDuXWGyeE33QFXGchb2VFWc4Z7945d";
122126

123127
/// Provides a `Read` interface that converts multiple parts into the protocol
124128
/// identified by [RFC2387](https://tools.ietf.org/html/rfc2387).
125129
/// **Note**: This implementation is just as rich as it needs to be to perform uploads
126130
/// to google APIs, and might not be a fully-featured implementation.
127131
#[derive(Default)]
128132
pub struct MultiPartReader<'a> {
129-
raw_parts: Vec<(hyper::header::Headers, &'a mut Read)>,
133+
raw_parts: Vec<(Headers, &'a mut Read)>,
130134
current_part: Option<(Cursor<Vec<u8>>, &'a mut Read)>,
135+
last_part_boundary: Option<Cursor<Vec<u8>>>,
131136
}
132137

133138
impl<'a> MultiPartReader<'a> {
134139

140+
/// Reserve memory for exactly the given amount of parts
141+
pub fn reserve_exact(&mut self, cap: usize) {
142+
self.raw_parts.reserve_exact(cap);
143+
}
144+
135145
/// Add a new part to the queue of parts to be read on the first `read` call.
136146
///
137147
/// # Arguments
@@ -145,15 +155,88 @@ impl<'a> MultiPartReader<'a> {
145155
/// # Panics
146156
///
147157
/// If this method is called after the first `read` call, it will panic
148-
pub fn add_part(mut self, reader: &'a mut Read, size: u64, mime_type: &mime::Mime) -> MultiPartReader<'a> {
149-
// let mut headers = hyper::header::Headers::
150-
// raw_parts.push((headers, reader));
158+
pub fn add_part(&mut self, reader: &'a mut Read, size: u64, mime_type: Mime) -> &mut MultiPartReader<'a> {
159+
let mut headers = Headers::new();
160+
headers.set(ContentType(mime_type));
161+
headers.set(ContentLength(size));
162+
self.raw_parts.push((headers, reader));
151163
self
152164
}
165+
166+
/// Returns the mime-type representing our multi-part message.
167+
/// Use it with the ContentType header.
168+
pub fn mime_type(&self) -> Mime {
169+
Mime(
170+
TopLevel::Multipart,
171+
SubLevel::Ext("Related".to_string()),
172+
vec![(Attr::Ext("boundary".to_string()), Value::Ext(BOUNDARY.to_string()))],
173+
)
174+
}
175+
176+
/// Returns true if we are totally used
177+
fn is_depleted(&self) -> bool {
178+
self.raw_parts.len() == 0 && self.current_part.is_none() && self.last_part_boundary.is_none()
179+
}
180+
181+
/// Returns true if we are handling our last part
182+
fn is_last_part(&self) -> bool {
183+
self.raw_parts.len() == 0 && self.current_part.is_some()
184+
}
153185
}
154186

155187
impl<'a> Read for MultiPartReader<'a> {
156188
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
157-
Err(io::Error::from_os_error(0))
189+
if self.last_part_boundary.is_some() {
190+
let br = self.last_part_boundary.as_mut().unwrap().read(buf).unwrap_or(0);
191+
if br < buf.len() {
192+
self.last_part_boundary = None;
193+
}
194+
return Ok(br)
195+
} else if self.is_depleted() {
196+
return Ok(0)
197+
} else if self.raw_parts.len() > 0 && self.current_part.is_none() {
198+
let (headers, reader) = self.raw_parts.remove(0);
199+
let mut c = Cursor::new(Vec::<u8>::new());
200+
write!(&mut c, "{}--{}{}{}{}", LINE_ENDING, BOUNDARY, LINE_ENDING,
201+
headers, LINE_ENDING).unwrap();
202+
c.seek(SeekFrom::Start(0)).unwrap();
203+
self.current_part = Some((c, reader));
204+
}
205+
// read headers as long as possible
206+
let (hb, rr) = {
207+
let &mut (ref mut c, ref mut reader) = self.current_part.as_mut().unwrap();
208+
let b = c.read(buf).unwrap_or(0);
209+
(b, reader.read(&mut buf[b..]))
210+
};
211+
212+
match rr {
213+
Ok(bytes_read) => {
214+
if hb < buf.len() && bytes_read == 0 {
215+
if self.is_last_part() {
216+
// before clearing the last part, we will add the boundary that
217+
// will be written last
218+
self.last_part_boundary = Some(Cursor::new(
219+
format!("{}--{}", LINE_ENDING, BOUNDARY).into_bytes()))
220+
}
221+
// We are depleted - this can trigger the next part to come in
222+
self.current_part = None;
223+
}
224+
let mut total_bytes_read = hb + bytes_read;
225+
while total_bytes_read < buf.len() && !self.is_depleted() {
226+
match self.read(&mut buf[total_bytes_read ..]) {
227+
Ok(br) => total_bytes_read += br,
228+
Err(err) => return Err(err),
229+
}
230+
}
231+
Ok(total_bytes_read)
232+
}
233+
Err(err) => {
234+
// fail permanently
235+
self.current_part = None;
236+
self.last_part_boundary = None;
237+
self.raw_parts.clear();
238+
Err(err)
239+
}
240+
}
158241
}
159242
}

0 commit comments

Comments
 (0)