Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changing blob to use arc pointers in order to limit wasteful copying … #8860

Merged
merged 1 commit into from Jan 7, 2016
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -8,19 +8,73 @@ use dom::bindings::error::Fallible;
use dom::bindings::global::{GlobalField, GlobalRef};
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::trace::JSTraceable;
use num::ToPrimitive;
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use std::cmp::{max, min};
use std::sync::mpsc::Sender;
use std::sync::Arc;
use util::str::DOMString;

#[derive(Clone, JSTraceable)]
pub struct DataSlice {
bytes: Arc<Vec<u8>>,
bytes_start: usize,
bytes_end: usize
}

impl DataSlice {
pub fn new(bytes: Arc<Vec<u8>>, start: Option<i64>, end: Option<i64>) -> DataSlice {
let size = bytes.len() as i64;
let relativeStart: i64 = match start {
None => 0,
Some(start) => {
if start < 0 {
max(size + start, 0)
} else {
min(start, size)
}
}
};
let relativeEnd: i64 = match end {
None => size,
Some(end) => {
if end < 0 {
max(size + end, 0)
} else {
min(end, size)
}
}
};

let span: i64 = max(relativeEnd - relativeStart, 0);
let start = relativeStart.to_usize().unwrap();
let end = (relativeStart + span).to_usize().unwrap();

DataSlice {
bytes: bytes,
bytes_start: start,
bytes_end: end
}
}

pub fn get_bytes(&self) -> &[u8] {
&self.bytes[self.bytes_start..self.bytes_end]
}

pub fn size(&self) -> u64 {
(self.bytes_end as u64) - (self.bytes_start as u64)
}
}


// https://w3c.github.io/FileAPI/#blob
#[dom_struct]
pub struct Blob {
reflector_: Reflector,
bytes: Option<Vec<u8>>,
#[ignore_heap_size_of = "No clear owner"]
data: DataSlice,
typeString: String,
global: GlobalField,
isClosed_: Cell<bool>,
@@ -33,25 +87,38 @@ fn is_ascii_printable(string: &str) -> bool {
}

impl Blob {
pub fn new_inherited(global: GlobalRef, bytes: Option<Vec<u8>>, typeString: &str) -> Blob {
pub fn new_inherited(global: GlobalRef,
bytes: Arc<Vec<u8>>,
bytes_start: Option<i64>,
bytes_end: Option<i64>,
typeString: &str) -> Blob {
Blob {
reflector_: Reflector::new(),
bytes: bytes,
data: DataSlice::new(bytes, bytes_start, bytes_end),
typeString: typeString.to_owned(),
global: GlobalField::from_rooted(&global),
isClosed_: Cell::new(false),
}
}

pub fn new(global: GlobalRef, bytes: Option<Vec<u8>>, typeString: &str) -> Root<Blob> {
reflect_dom_object(box Blob::new_inherited(global, bytes, typeString),
global,
BlobBinding::Wrap)
pub fn new(global: GlobalRef, bytes: Vec<u8>, typeString: &str) -> Root<Blob> {
let boxed_blob = box Blob::new_inherited(global, Arc::new(bytes), None, None, typeString);
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
}

fn new_sliced(global: GlobalRef,
bytes: Arc<Vec<u8>>,
bytes_start: Option<i64>,
bytes_end: Option<i64>,
typeString: &str) -> Root<Blob> {

let boxed_blob = box Blob::new_inherited(global, bytes, bytes_start, bytes_end, typeString);
reflect_dom_object(boxed_blob, global, BlobBinding::Wrap)
}

// https://w3c.github.io/FileAPI/#constructorBlob
pub fn Constructor(global: GlobalRef) -> Fallible<Root<Blob>> {
Ok(Blob::new(global, None, ""))
Ok(Blob::new(global, Vec::new(), ""))
}

// https://w3c.github.io/FileAPI/#constructorBlob
@@ -61,7 +128,7 @@ impl Blob {
-> Fallible<Root<Blob>> {
// TODO: accept other blobParts types - ArrayBuffer or ArrayBufferView or Blob
// FIXME(ajeffrey): convert directly from a DOMString to a Vec<u8>
let bytes: Option<Vec<u8>> = Some(String::from(blobParts).into_bytes());
let bytes: Vec<u8> = String::from(blobParts).into_bytes();
let typeString = if is_ascii_printable(&blobPropertyBag.type_) {
&*blobPropertyBag.type_
} else {
@@ -70,23 +137,15 @@ impl Blob {
Ok(Blob::new(global, bytes, &typeString.to_ascii_lowercase()))
}

pub fn read_out_buffer(&self, send: Sender<Vec<u8>>) {
send.send(self.bytes.clone().unwrap_or(vec![])).unwrap();
}

// simpler to use version of read_out_buffer
pub fn clone_bytes(&self) -> Vec<u8> {
self.bytes.clone().unwrap_or(vec![])
pub fn get_data(&self) -> &DataSlice {
&self.data
}
}

impl BlobMethods for Blob {
// https://w3c.github.io/FileAPI/#dfn-size
fn Size(&self) -> u64 {
match self.bytes {
None => 0,
Some(ref bytes) => bytes.len() as u64,
}
self.data.size()
}

// https://w3c.github.io/FileAPI/#dfn-type
@@ -100,27 +159,7 @@ impl BlobMethods for Blob {
end: Option<i64>,
contentType: Option<DOMString>)
-> Root<Blob> {
let size: i64 = self.Size().to_i64().unwrap();
let relativeStart: i64 = match start {
None => 0,
Some(start) => {
if start < 0 {
max(size.to_i64().unwrap() + start, 0)
} else {
min(start, size)
}
}
};
let relativeEnd: i64 = match end {
None => size,
Some(end) => {
if end < 0 {
max(size + end, 0)
} else {
min(end, size)
}
}
};

let relativeContentType = match contentType {
None => DOMString::new(),
Some(mut str) => {
@@ -132,18 +171,9 @@ impl BlobMethods for Blob {
}
}
};
let span: i64 = max(relativeEnd - relativeStart, 0);
let global = self.global.root();
match self.bytes {
None => Blob::new(global.r(), None, &relativeContentType),
Some(ref vec) => {
let start = relativeStart.to_usize().unwrap();
let end = (relativeStart + span).to_usize().unwrap();
let mut bytes: Vec<u8> = Vec::new();
bytes.extend_from_slice(&vec[start..end]);
Blob::new(global.r(), Some(bytes), &relativeContentType)
}
}
let bytes = self.data.bytes.clone();
Blob::new_sliced(global.r(), bytes, start, end, &relativeContentType)
}

// https://w3c.github.io/FileAPI/#dfn-isClosed
@@ -8,6 +8,7 @@ use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::reflector::reflect_dom_object;
use dom::blob::Blob;
use std::sync::Arc;
use util::str::DOMString;

#[dom_struct]
@@ -21,7 +22,7 @@ impl File {
_file_bits: &Blob, name: DOMString) -> File {
File {
//TODO: get type from the underlying filesystem instead of "".to_string()
blob: Blob::new_inherited(global, None, ""),
blob: Blob::new_inherited(global, Arc::new(Vec::new()), None, None, ""),
name: name,
}
// XXXManishearth Once Blob is able to store data
@@ -12,7 +12,7 @@ use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, MutNullableHeap, Root};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::blob::Blob;
use dom::blob::{Blob, DataSlice};
use dom::domexception::{DOMErrorName, DOMException};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
@@ -23,10 +23,8 @@ use encoding::types::{DecoderTrap, EncodingRef};
use hyper::mime::{Attr, Mime};
use rustc_serialize::base64::{CharacterSet, Config, Newline, ToBase64};
use script_task::ScriptTaskEventCategory::FileRead;
use script_task::{CommonScriptMsg, Runnable, ScriptChan, ScriptPort};
use script_task::{CommonScriptMsg, Runnable, ScriptChan};
use std::cell::Cell;
use std::sync::mpsc;
use std::sync::mpsc::Receiver;
use string_cache::Atom;
use util::str::DOMString;
use util::task::spawn_named;
@@ -163,7 +161,7 @@ impl FileReader {

// https://w3c.github.io/FileAPI/#dfn-readAsText
pub fn process_read_eof(filereader: TrustedFileReader, gen_id: GenerationId,
data: ReadMetaData, blob_contents: Vec<u8>) {
data: ReadMetaData, blob_contents: DataSlice) {
let fr = filereader.root();

macro_rules! return_on_abort(
@@ -178,11 +176,13 @@ impl FileReader {
// Step 8.1
fr.change_ready_state(FileReaderReadyState::Done);
// Step 8.2

let bytes = blob_contents.get_bytes();
let output = match data.function {
FileReaderFunction::ReadAsDataUrl =>
FileReader::perform_readasdataurl(data, blob_contents),
FileReader::perform_readasdataurl(data, bytes),
FileReaderFunction::ReadAsText =>
FileReader::perform_readastext(data, blob_contents),
FileReader::perform_readastext(data, bytes),
};

*fr.result.borrow_mut() = Some(output);
@@ -200,12 +200,11 @@ impl FileReader {
}

// https://w3c.github.io/FileAPI/#dfn-readAsText
fn perform_readastext(data: ReadMetaData, blob_contents: Vec<u8>)
fn perform_readastext(data: ReadMetaData, blob_bytes: &[u8])
-> DOMString {

let blob_label = &data.label;
let blob_type = &data.blobtype;
let blob_bytes = &blob_contents[..];

//https://w3c.github.io/FileAPI/#encoding-determination
// Steps 1 & 2 & 3
@@ -233,15 +232,15 @@ impl FileReader {
}

//https://w3c.github.io/FileAPI/#dfn-readAsDataURL
fn perform_readasdataurl(data: ReadMetaData, blob_contents: Vec<u8>)
fn perform_readasdataurl(data: ReadMetaData, bytes: &[u8])
-> DOMString {
let config = Config {
char_set: CharacterSet::UrlSafe,
newline: Newline::LF,
pad: true,
line_length: None
};
let base64 = blob_contents.to_base64(config);
let base64 = bytes.to_base64(config);

let output = if data.blobtype.is_empty() {
format!("data:base64,{}", base64)
@@ -355,8 +354,8 @@ impl FileReader {
self.change_ready_state(FileReaderReadyState::Loading);

// Step 4
let (send, bytes) = mpsc::channel();
blob.read_out_buffer(send);
let blob_contents = blob.get_data().clone();

let type_ = blob.Type();

let load_data = ReadMetaData::new(String::from(type_), label.map(String::from), function);
@@ -367,7 +366,7 @@ impl FileReader {
let script_chan = global.file_reading_task_source();

spawn_named("file reader async operation".to_owned(), move || {
perform_annotated_read_operation(gen_id, load_data, bytes, fr, script_chan)
perform_annotated_read_operation(gen_id, load_data, blob_contents, fr, script_chan)
});
Ok(())
}
@@ -382,7 +381,7 @@ pub enum FileReaderEvent {
ProcessRead(TrustedFileReader, GenerationId),
ProcessReadData(TrustedFileReader, GenerationId),
ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName),
ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, Vec<u8>)
ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, DataSlice)
}

impl Runnable for FileReaderEvent {
@@ -406,7 +405,7 @@ impl Runnable for FileReaderEvent {
}

// https://w3c.github.io/FileAPI/#task-read-operation
fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: Receiver<Vec<u8>>,
fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, blob_contents: DataSlice,
filereader: TrustedFileReader, script_chan: Box<ScriptChan + Send>) {
let chan = &script_chan;
// Step 4
@@ -416,16 +415,6 @@ fn perform_annotated_read_operation(gen_id: GenerationId, data: ReadMetaData, bl
let task = box FileReaderEvent::ProcessReadData(filereader.clone(), gen_id);
chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();

let bytes = match blob_contents.recv() {
Ok(bytes) => bytes,
Err(_) => {
let task = box FileReaderEvent::ProcessReadError(filereader,
gen_id, DOMErrorName::NotFoundError);
chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
return;
}
};

let task = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, bytes);
let task = box FileReaderEvent::ProcessReadEOF(filereader, gen_id, data, blob_contents);
chan.send(CommonScriptMsg::RunnableMsg(FileRead, task)).unwrap();
}
@@ -85,7 +85,7 @@ impl TestBindingMethods for TestBinding {
fn EnumAttribute(&self) -> TestEnum { TestEnum::_empty }
fn SetEnumAttribute(&self, _: TestEnum) {}
fn InterfaceAttribute(&self) -> Root<Blob> {
Blob::new(global_root_from_reflector(self).r(), None, "")
Blob::new(global_root_from_reflector(self).r(), Vec::new(), "")
}
fn SetInterfaceAttribute(&self, _: &Blob) {}
fn UnionAttribute(&self) -> HTMLElementOrLong { HTMLElementOrLong::eLong(0) }
@@ -143,7 +143,7 @@ impl TestBindingMethods for TestBinding {
fn SetAttr_to_automatically_rename(&self, _: DOMString) {}
fn GetEnumAttributeNullable(&self) -> Option<TestEnum> { Some(TestEnum::_empty) }
fn GetInterfaceAttributeNullable(&self) -> Option<Root<Blob>> {
Some(Blob::new(global_root_from_reflector(self).r(), None, ""))
Some(Blob::new(global_root_from_reflector(self).r(), Vec::new(), ""))
}
fn SetInterfaceAttributeNullable(&self, _: Option<&Blob>) {}
fn GetInterfaceAttributeWeak(&self) -> Option<Root<URL>> {
@@ -182,7 +182,7 @@ impl TestBindingMethods for TestBinding {
fn ReceiveByteString(&self) -> ByteString { ByteString::new(vec!()) }
fn ReceiveEnum(&self) -> TestEnum { TestEnum::_empty }
fn ReceiveInterface(&self) -> Root<Blob> {
Blob::new(global_root_from_reflector(self).r(), None, "")
Blob::new(global_root_from_reflector(self).r(), Vec::new(), "")
}
fn ReceiveAny(&self, _: *mut JSContext) -> JSVal { NullValue() }
fn ReceiveObject(&self, _: *mut JSContext) -> *mut JSObject { panic!() }
@@ -207,7 +207,7 @@ impl TestBindingMethods for TestBinding {
fn ReceiveNullableByteString(&self) -> Option<ByteString> { Some(ByteString::new(vec!())) }
fn ReceiveNullableEnum(&self) -> Option<TestEnum> { Some(TestEnum::_empty) }
fn ReceiveNullableInterface(&self) -> Option<Root<Blob>> {
Some(Blob::new(global_root_from_reflector(self).r(), None, ""))
Some(Blob::new(global_root_from_reflector(self).r(), Vec::new(), ""))
}
fn ReceiveNullableObject(&self, _: *mut JSContext) -> *mut JSObject { ptr::null_mut() }
fn ReceiveNullableUnion(&self) -> Option<HTMLElementOrLong> {
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.