web-sys: Add support for Global-scope methods

This commit adds further support for the `Global` attribute to not only emit
structural accessors but also emit functions that don't take `&self`. All
methods on a `[Global]` interface will not require `&self` and will call
functions and/or access properties on the global scope.

This should enable things like:

    Window::location() // returns `Location`
    Window::fetch(...) // invokes the `fetch` function

Closes #659
This commit is contained in:
Alex Crichton
2018-08-28 15:19:31 -07:00
parent 447b42b7ac
commit 36b854b69c
16 changed files with 296 additions and 202 deletions

View File

@ -99,6 +99,10 @@ pub enum ImportFunctionKind {
ty: syn::Type,
kind: MethodKind,
},
ScopedMethod {
ty: syn::Type,
operation: Operation,
},
Normal,
}
@ -407,6 +411,29 @@ impl ImportFunction {
}
fn shared(&self) -> shared::ImportFunction {
let shared_operation = |operation: &Operation| {
let is_static = operation.is_static;
let kind = match &operation.kind {
OperationKind::Regular => shared::OperationKind::Regular,
OperationKind::Getter(g) => {
let g = g.as_ref().map(|g| g.to_string());
shared::OperationKind::Getter(
g.unwrap_or_else(|| self.infer_getter_property()),
)
}
OperationKind::Setter(s) => {
let s = s.as_ref().map(|s| s.to_string());
shared::OperationKind::Setter(
s.unwrap_or_else(|| self.infer_setter_property()),
)
}
OperationKind::IndexingGetter => shared::OperationKind::IndexingGetter,
OperationKind::IndexingSetter => shared::OperationKind::IndexingSetter,
OperationKind::IndexingDeleter => shared::OperationKind::IndexingDeleter,
};
shared::Operation { is_static, kind }
};
let method = match self.kind {
ImportFunctionKind::Method {
ref class,
@ -415,34 +442,21 @@ impl ImportFunction {
} => {
let kind = match kind {
MethodKind::Constructor => shared::MethodKind::Constructor,
MethodKind::Operation(Operation { is_static, kind }) => {
let is_static = *is_static;
let kind = match kind {
OperationKind::Regular => shared::OperationKind::Regular,
OperationKind::Getter(g) => {
let g = g.as_ref().map(|g| g.to_string());
shared::OperationKind::Getter(
g.unwrap_or_else(|| self.infer_getter_property()),
)
}
OperationKind::Setter(s) => {
let s = s.as_ref().map(|s| s.to_string());
shared::OperationKind::Setter(
s.unwrap_or_else(|| self.infer_setter_property()),
)
}
OperationKind::IndexingGetter => shared::OperationKind::IndexingGetter,
OperationKind::IndexingSetter => shared::OperationKind::IndexingSetter,
OperationKind::IndexingDeleter => shared::OperationKind::IndexingDeleter,
};
shared::MethodKind::Operation(shared::Operation { is_static, kind })
MethodKind::Operation(op) => {
shared::MethodKind::Operation(shared_operation(op))
}
};
Some(shared::MethodData {
class: class.clone(),
class: Some(class.clone()),
kind,
})
}
ImportFunctionKind::ScopedMethod { ref operation, .. } => {
Some(shared::MethodData {
class: None,
kind: shared::MethodKind::Operation(shared_operation(operation)),
})
}
ImportFunctionKind::Normal => None,
};

View File

@ -784,6 +784,9 @@ impl TryToTokens for ast::ImportFunction {
}
class_ty = Some(ty);
}
ast::ImportFunctionKind::ScopedMethod { ref ty, .. } => {
class_ty = Some(ty);
}
ast::ImportFunctionKind::Normal => {}
}
let vis = &self.function.rust_vis;

View File

@ -246,6 +246,7 @@ impl ImportedTypes for ast::ImportFunctionKind {
{
match self {
ast::ImportFunctionKind::Method { ty, .. } => ty.imported_types(f),
ast::ImportFunctionKind::ScopedMethod { ty, .. } => ty.imported_types(f),
ast::ImportFunctionKind::Normal => {}
}
}