Skip to content

Commit

Permalink
web-sys services conversion (#827)
Browse files Browse the repository at this point in the history
* Convert `console`.

* Finish services.

* Some polish.

* Fix `ArrayBuffer` to `Uint8Array` conversions.

* Fix aborting fetch leading to error and some polish.

* Replaced some `unwrap`s with `expect`s.

* Use `cfg_if` and `cfg_match` and do some polish.

* Proper scoping.

* Some fixes.

* Move fetch and reader services to different PR.

* Revert split.
  • Loading branch information
daxpedda authored and jstarry committed Jan 15, 2020
1 parent 3b3fa96 commit c1f621a
Show file tree
Hide file tree
Showing 11 changed files with 534 additions and 176 deletions.
98 changes: 79 additions & 19 deletions src/services/console.rs
@@ -1,7 +1,16 @@
//! This module contains a service implementation to use browser's console.

#[allow(unused_imports)]
use stdweb::{_js_impl, js};
use cfg_if::cfg_if;
use cfg_match::cfg_match;
cfg_if! {
if #[cfg(feature = "std_web")] {
#[allow(unused_imports)]
use stdweb::{_js_impl, js};
} else if #[cfg(feature = "web_sys")] {
use wasm_bindgen::JsValue;
use web_sys::console;
}
}

/// A service to use methods of a
/// [Console](https://developer.mozilla.org/en-US/docs/Web/API/Console).
Expand All @@ -17,101 +26,152 @@ impl ConsoleService {
/// [console.log](https://developer.mozilla.org/en-US/docs/Web/API/Console/log)
/// method implementation.
pub fn log(&mut self, message: &str) {
js! { @(no_return) console.log(@{message}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.log(@{message}); },
feature = "web_sys" => console::log_1(&JsValue::from_str(message)),
};
}

/// [console.warn](https://developer.mozilla.org/en-US/docs/Web/API/Console/warn)
/// method implementation.
pub fn warn(&mut self, message: &str) {
js! { @(no_return) console.warn(@{message}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.warn(@{message}); },
feature = "web_sys" => console::warn_1(&JsValue::from_str(message)),
};
}

/// [console.info](https://developer.mozilla.org/en-US/docs/Web/API/Console/info)
/// method implementation.
pub fn info(&mut self, message: &str) {
js! { @(no_return) console.info(@{message}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.info(@{message}); },
feature = "web_sys" => console::info_1(&JsValue::from_str(message)),
};
}

/// [console.error](https://developer.mozilla.org/en-US/docs/Web/API/Console/error)
/// method implementation.
pub fn error(&mut self, message: &str) {
js! { @(no_return) console.error(@{message}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.error(@{message}); },
feature = "web_sys" => console::error_1(&JsValue::from_str(message)),
};
}

/// [console.debug](https://developer.mozilla.org/en-US/docs/Web/API/Console/debug)
/// method implementation.
pub fn debug(&mut self, message: &str) {
js! { @(no_return) console.debug(@{message}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.debug(@{message}); },
feature = "web_sys" => console::debug_1(&JsValue::from_str(message)),
};
}

/// [console.count_named](https://developer.mozilla.org/en-US/docs/Web/API/Console/count_named)
/// method implementation.
pub fn count_named(&mut self, name: &str) {
js! { @(no_return) console.count(@{name}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.count(@{name}); },
feature = "web_sys" => console::count_with_label(name),
};
}

/// [console.count](https://developer.mozilla.org/en-US/docs/Web/API/Console/count)
/// method implementation.
pub fn count(&mut self) {
js! { @(no_return) console.count(); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.count(); },
feature = "web_sys" => console::count(),
};
}

/// [console.time_named](https://developer.mozilla.org/en-US/docs/Web/API/Console/time_named)
/// method implementation.
pub fn time_named(&mut self, name: &str) {
js! { @(no_return) console.time(@{name}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.time(@{name}); },
feature = "web_sys" => console::time_with_label(name),
};
}

/// [console.time_named_end](https://developer.mozilla.org/en-US/docs/Web/API/Console/time_named_end)
/// method implementation.
pub fn time_named_end(&mut self, name: &str) {
js! { @(no_return) console.timeEnd(@{name}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.timeEnd(@{name}); },
feature = "web_sys" => console::time_end_with_label(name),
};
}

/// [console.time](https://developer.mozilla.org/en-US/docs/Web/API/Console/time)
/// method implementation.
pub fn time(&mut self) {
js! { @(no_return) console.time(); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.time(); },
feature = "web_sys" => console::time(),
};
}
/// [console.time_end](https://developer.mozilla.org/en-US/docs/Web/API/Console/time_end)
/// method implementation.
pub fn time_end(&mut self) {
js! { @(no_return) console.timeEnd(); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.timeEnd(); },
feature = "web_sys" => console::time_end(),
};
}

/// [console.clear](https://developer.mozilla.org/en-US/docs/Web/API/Console/clear)
/// method implementation.
pub fn clear(&mut self) {
js! { @(no_return) console.clear(); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.clear(); },
feature = "web_sys" => console::clear(),
};
}

/// [console.group](https://developer.mozilla.org/en-US/docs/Web/API/Console/group)
/// method implementation.
pub fn group(&mut self) {
js! { @(no_return) console.group(); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.group(); },
feature = "web_sys" => console::group_0(),
};
}

/// [console.group_collapsed](https://developer.mozilla.org/en-US/docs/Web/API/Console/group_collapsed)
/// method implementation.
pub fn group_collapsed(&mut self) {
js! { @(no_return) console.groupCollapsed(); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.groupCollapsed(); },
feature = "web_sys" => console::group_collapsed_0(),
};
}

/// [console.group_end](https://developer.mozilla.org/en-US/docs/Web/API/Console/group_end)
/// method implementation.
pub fn group_end(&mut self) {
js! { @(no_return) console.groupEnd(); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.groupEnd(); },
feature = "web_sys" => console::group_end(),
};
}

/// [console.trace](https://developer.mozilla.org/en-US/docs/Web/API/Console/trace)
/// method implementation.
pub fn trace(&mut self) {
js! { @(no_return) console.trace(); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.trace(); },
feature = "web_sys" => console::trace_0(),
};
}

/// [console.assert](https://developer.mozilla.org/en-US/docs/Web/API/Console/assert)
/// method implementation.
pub fn assert(&mut self, condition: bool, message: &str) {
js! { @(no_return) console.assert(@{condition}, @{message}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) console.assert(@{condition}, @{message}); },
feature = "web_sys" => console::assert_with_condition_and_data_1(condition, &String::from(message).into()),
};
}
}
32 changes: 24 additions & 8 deletions src/services/dialog.rs
@@ -1,9 +1,17 @@
//! This module contains the implementation of a service
//! to show alerts and confirm dialogs in a browser.

use stdweb::Value;
#[allow(unused_imports)]
use stdweb::{_js_impl, js};
use cfg_if::cfg_if;
use cfg_match::cfg_match;
cfg_if! {
if #[cfg(feature = "std_web")] {
use stdweb::Value;
#[allow(unused_imports)]
use stdweb::{_js_impl, js};
} else if #[cfg(feature = "web_sys")] {
use crate::utils;
}
}

/// A dialog service.
#[derive(Default, Debug)]
Expand All @@ -18,16 +26,24 @@ impl DialogService {
/// Calls [alert](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert)
/// function.
pub fn alert(&mut self, message: &str) {
js! { @(no_return) alert(@{message}); }
cfg_match! {
feature = "std_web" => js! { @(no_return) alert(@{message}); },
feature = "web_sys" => utils::window().alert_with_message(message).unwrap(),
};
}

/// Calls [confirm](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
/// function.
pub fn confirm(&mut self, message: &str) -> bool {
let value: Value = js! { return confirm(@{message}); };
match value {
Value::Bool(result) => result,
_ => false,
cfg_match! {
feature = "std_web" => ({
let value: Value = js! { return confirm(@{message}); };
match value {
Value::Bool(result) => result,
_ => false,
}
}),
feature = "web_sys" => utils::window().confirm_with_message(message).unwrap(),
}
}
}
14 changes: 7 additions & 7 deletions src/services/fetch.rs
Expand Up @@ -3,7 +3,6 @@
use super::Task;
use crate::callback::Callback;
use crate::format::{Binary, Format, Text};
use failure::Fail;
use serde::Serialize;
use std::collections::HashMap;
use std::fmt;
Expand All @@ -13,6 +12,7 @@ use stdweb::web::ArrayBuffer;
use stdweb::{JsSerialize, Value};
#[allow(unused_imports)]
use stdweb::{_js_impl, js};
use thiserror::Error;

pub use http::{HeaderMap, Method, Request, Response, StatusCode, Uri};

Expand Down Expand Up @@ -90,9 +90,9 @@ pub struct FetchOptions {
}

/// Represents errors of a fetch service.
#[derive(Debug, Fail)]
#[derive(Debug, Error)]
enum FetchError {
#[fail(display = "failed response")]
#[error("failed response")]
FailedResponse,
}

Expand Down Expand Up @@ -157,10 +157,10 @@ impl FetchService {
///# fn dont_execute() {
///# let link: ComponentLink<Comp> = unimplemented!();
///# let mut fetch_service: FetchService = FetchService::new();
///# let post_request: Request<Result<String, failure::Error>> = unimplemented!();
///# let post_request: Request<Result<String, anyhow::Error>> = unimplemented!();
/// let task = fetch_service.fetch(
/// post_request,
/// link.callback(|response: Response<Result<String, failure::Error>>| {
/// link.callback(|response: Response<Result<String, anyhow::Error>>| {
/// if response.status().is_success() {
/// Msg::Noop
/// } else {
Expand Down Expand Up @@ -201,7 +201,7 @@ impl FetchService {
///# fn dont_execute() {
///# let link: ComponentLink<Comp> = unimplemented!();
/// let get_request = Request::get("/thing").body(Nothing).unwrap();
/// let callback = link.callback(|response: Response<Json<Result<Data, failure::Error>>>| {
/// let callback = link.callback(|response: Response<Json<Result<Data, anyhow::Error>>>| {
/// if let (meta, Json(Ok(body))) = response.into_parts() {
/// if meta.status.is_success() {
/// return Msg::FetchResourceComplete(body);
Expand Down Expand Up @@ -245,7 +245,7 @@ impl FetchService {
///# pub enum Msg {}
///# fn dont_execute() {
///# let link: ComponentLink<Comp> = unimplemented!();
///# let callback = link.callback(|response: Response<Result<String, failure::Error>>| unimplemented!());
///# let callback = link.callback(|response: Response<Result<String, anyhow::Error>>| unimplemented!());
/// let request = fetch::Request::get("/path/")
/// .body(Nothing)
/// .unwrap();
Expand Down
51 changes: 35 additions & 16 deletions src/services/interval.rs
Expand Up @@ -3,16 +3,27 @@

use super::{to_ms, Task};
use crate::callback::Callback;
use cfg_if::cfg_if;
use cfg_match::cfg_match;
use std::fmt;
use std::time::Duration;
use stdweb::Value;
#[allow(unused_imports)]
use stdweb::{_js_impl, js};
cfg_if! {
if #[cfg(feature = "std_web")] {
use stdweb::Value;
#[allow(unused_imports)]
use stdweb::{_js_impl, js};
} else if #[cfg(feature = "web_sys")] {
use gloo::timers::callback::Interval;
}
}

/// A handle which helps to cancel interval. Uses
/// [clearInterval](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval).
#[must_use]
pub struct IntervalTask(Option<Value>);
pub struct IntervalTask(
#[cfg(feature = "std_web")] Option<Value>,
#[cfg(feature = "web_sys")] Option<Interval>,
);

impl fmt::Debug for IntervalTask {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand All @@ -37,16 +48,19 @@ impl IntervalService {
callback.emit(());
};
let ms = to_ms(duration);
let handle = js! {
var callback = @{callback};
var action = function() {
callback();
};
var delay = @{ms};
return {
interval_id: setInterval(action, delay),
callback: callback,
};
let handle = cfg_match! {
feature = "std_web" => js! {
var callback = @{callback};
var action = function() {
callback();
};
var delay = @{ms};
return {
interval_id: setInterval(action, delay),
callback: callback,
};
},
feature = "web_sys" => Interval::new(ms, callback),
};
IntervalTask(Some(handle))
}
Expand All @@ -57,7 +71,9 @@ impl Task for IntervalTask {
self.0.is_some()
}
fn cancel(&mut self) {
#[cfg_attr(feature = "web_sys", allow(unused_variables))]
let handle = self.0.take().expect("tried to cancel interval twice");
#[cfg(feature = "std_web")]
js! { @(no_return)
var handle = @{handle};
clearInterval(handle.interval_id);
Expand All @@ -68,8 +84,11 @@ impl Task for IntervalTask {

impl Drop for IntervalTask {
fn drop(&mut self) {
if self.is_active() {
self.cancel();
#[cfg(feature = "std_web")]
{
if self.is_active() {
self.cancel();
}
}
}
}

0 comments on commit c1f621a

Please sign in to comment.