Skip to content

Commit

Permalink
Update MSRV to 1.63.0 and remove some unsafes (#470)
Browse files Browse the repository at this point in the history
* Update MSRV to 1.63.0

* Remove some unsafes from sycamore-reactive

* BREAKING: remove redundant Children::call_with_bounded_scope

* Fix clippy lints introduced in 1.63.0

* Update ui tests for 1.63.0
  • Loading branch information
lukechu10 authored Aug 21, 2022
1 parent 2bb51c3 commit 75be1ca
Show file tree
Hide file tree
Showing 13 changed files with 53 additions and 58 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
rust:
- 1.58.0
- 1.63.0
- stable
- nightly
os:
Expand Down Expand Up @@ -53,13 +53,13 @@ jobs:
run: cd packages/sycamore && cargo test

- name: Run tests with all features
if: matrix.rust == '1.58.0'
if: matrix.rust == '1.63.0'
env:
RUN_UI_TESTS: true
run: cargo test --all-features

- name: Run tests with all features excluding UI
if: matrix.rust != '1.58.0'
if: matrix.rust != '1.63.0'
run: cargo test --all-features

- name: Run headless browser tests
Expand Down
4 changes: 2 additions & 2 deletions docs/next/getting_started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ rustup target add wasm32-unknown-unknown

### Minimum Supported Rust Version (MSRV) and Rust edition

The minimum supported Rust toolchain is `v1.58.0`. Sycamore is not guaranteed to compile on an older
version of Rust.
The minimum supported Rust toolchain is `v1.63.0`. Sycamore is not guaranteed to (and probably
won't) compile on older versions of Rust.

Sycamore only works on Rust edition 2021. Even though most crates written in edition 2021 are
backward compatible with older editions, this is not the case for Sycamore because Sycamore's
Expand Down
2 changes: 1 addition & 1 deletion examples/transitions/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn App<G: Html>(cx: Scope) -> View<G> {
view! { cx,
div {
p { "Suspense + Transitions" }
p { "Transition state: " (transition.is_pending().then(|| "pending").unwrap_or("done")) }
p { "Transition state: " (transition.is_pending().then_some("pending").unwrap_or("done")) }
button(on:click=move |_| update(Tab::One)) { "One" }
button(on:click=move |_| update(Tab::Two)) { "Two" }
button(on:click=move |_| update(Tab::Three)) { "Three" }
Expand Down
5 changes: 0 additions & 5 deletions packages/sycamore-core/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,6 @@ impl<'a, G: GenericNode> Children<'a, G> {
(self.f)(cx)
}

/// Instantiate the child [`View`] with the passed [`BoundedScope`].
pub fn call_with_bounded_scope(self, cx: BoundedScope<'_, 'a>) -> View<G> {
(self.f)(cx)
}

/// Create a new [`Children`] from a closure.
pub fn new(_cx: Scope<'a>, f: impl FnOnce(BoundedScope<'_, 'a>) -> View<G> + 'a) -> Self {
Self { f: Box::new(f) }
Expand Down
4 changes: 1 addition & 3 deletions packages/sycamore-core/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ impl<G: GenericNode> View<G> {
) -> Self {
let signal = create_ref(cx, RefCell::new(None::<RcSignal<View<G>>>));
create_effect_scoped(cx, move |cx| {
// SAFETY: `f` takes the same parameter as the child cx provided by
// `create_effect_scoped`.
let view = f(unsafe { std::mem::transmute(cx) });
let view = f(cx);
if signal.borrow().is_some() {
signal.borrow().as_ref().unwrap().set(view);
} else {
Expand Down
2 changes: 1 addition & 1 deletion packages/sycamore-macro/src/view/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! The `view!` macro implementation.
#![allow(clippy::eval_order_dependence)] // Needed when using `syn::parenthesized!`.
#![allow(clippy::mixed_read_write_in_expression)] // Needed when using `syn::parenthesized!`.

pub mod codegen;
pub mod ir;
Expand Down
2 changes: 1 addition & 1 deletion packages/sycamore-macro/src/view/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl Parse for Element {
}
// Check if dangerously_set_inner_html is also set.
let dangerously_set_inner_html_span = attrs.iter().find_map(|attr| {
(attr.ty == AttributeType::DangerouslySetInnerHtml).then(|| attr.span)
(attr.ty == AttributeType::DangerouslySetInnerHtml).then_some(attr.span)
});
if let Some(span) = dangerously_set_inner_html_span {
if !children.is_empty() {
Expand Down
37 changes: 27 additions & 10 deletions packages/sycamore-macro/tests/view/component-fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -20,46 +20,63 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied
--> tests/view/component-fail.rs:29:38
|
29 | let _: View<G> = view! { cx, Component(1) };
| -- ^^^^^^^^^ - supplied 2 arguments
| |
| expected 1 argument
| ^^^^^^^^^ - argument unexpected
|
note: function defined here
--> tests/view/component-fail.rs:17:4
|
17 | fn Component<G: Html>(cx: Scope) -> View<G> {
| ^^^^^^^^^ -
help: remove the extra argument
|
29 | let _: View<G> = Component(cx);
| ~~~~~~~~~~~~~

error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> tests/view/component-fail.rs:31:38
|
31 | let _: View<G> = view! { cx, PropComponent() };
| -- ^^^^^^^^^^^^^ expected 2 arguments
| |
| supplied 1 argument
| ^^^^^^^^^^^^^---- an argument of type `Prop` is missing
|
note: function defined here
--> tests/view/component-fail.rs:9:8
|
9 | pub fn PropComponent<G: Html>(cx: Scope, Prop { prop: _ }: Prop) -> View<G> {
| ^^^^^^^^^^^^^ ------------
help: provide the argument
|
31 | let _: View<G> = PropComponent(cx, /* Prop */);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0061]: this function takes 2 arguments but 1 argument was supplied
--> tests/view/component-fail.rs:32:38
|
32 | let _: View<G> = view! { cx, PropComponent {} };
| -- ^^^^^^^^^^^^^ expected 2 arguments
| |
| supplied 1 argument
| ^^^^^^^^^^^^^----- an argument of type `Prop` is missing
|
note: function defined here
--> tests/view/component-fail.rs:9:8
|
9 | pub fn PropComponent<G: Html>(cx: Scope, Prop { prop: _ }: Prop) -> View<G> {
| ^^^^^^^^^^^^^ ------------
help: provide the argument
|
32 | let _: View<G> = PropComponent(cx, /* Prop */);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0308]: mismatched types
--> tests/view/component-fail.rs:33:57
|
33 | let _: View<G> = view! { cx, PropComponent(prop=123) };
| ^^^ expected `&str`, found integer
| ---- ^^^ expected `&str`, found integer
| |
| arguments to this function are incorrect
|
note: associated function defined here
--> tests/view/component-fail.rs:5:5
|
3 | #[derive(Prop)]
| ----
4 | pub struct Prop {
5 | prop: &'static str,
| ^^^^
4 changes: 1 addition & 3 deletions packages/sycamore-reactive/src/effect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,7 @@ where
}
// Create a new nested scope and save the disposer.
let new_disposer: Option<ScopeDisposer<'a>> = Some(create_child_scope(cx, |cx| {
// SAFETY: f takes the same parameter as the argument to
// self.create_child_scope(_).
f(unsafe { std::mem::transmute(cx) });
f(cx);
}));
disposer = new_disposer;
});
Expand Down
22 changes: 6 additions & 16 deletions packages/sycamore-reactive/src/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ where
// TODO: do not clone T
for new_item in new_items.iter().cloned() {
let mut tmp = None;
let new_disposer = create_child_scope(cx, |cx| {
// SAFETY: f takes the same parameter as the argument to create_child_scope.
tmp = Some(map_fn(unsafe { mem::transmute(cx) }, new_item));
});
let new_disposer = create_child_scope(cx, |cx| tmp = Some(map_fn(cx, new_item)));
mapped.push(tmp.unwrap());
disposers.push(Some(new_disposer));
}
Expand Down Expand Up @@ -159,10 +156,8 @@ where
// Create new value.
let mut tmp = None;
let new_item = new_items[j].clone();
let new_disposer = create_child_scope(cx, |cx| {
// SAFETY: f takes the same parameter as the argument to create_child_scope.
tmp = Some(map_fn(unsafe { mem::transmute(cx) }, new_item));
});
let new_disposer =
create_child_scope(cx, |cx| tmp = Some(map_fn(cx, new_item)));
if mapped.len() > j {
mapped[j] = tmp.unwrap();
disposers[j] = Some(new_disposer);
Expand Down Expand Up @@ -249,17 +244,12 @@ where

let mut tmp = None;
if item.is_none() || eqs {
let new_disposer = create_child_scope(cx, |cx| {
// SAFETY: f takes the same parameter as the argument to
// create_child_scope(cx, _).
tmp = Some(map_fn(unsafe { mem::transmute(cx) }, new_item));
});
let new_disposer =
create_child_scope(cx, |cx| tmp = Some(map_fn(cx, new_item)));
if item.is_none() {
// SAFETY: tmp is written in create_child_scope.
mapped.push(tmp.unwrap());
disposers.push(new_disposer);
} else if eqs {
// SAFETY: tmp is written in create_child_scope.
mapped[i] = tmp.unwrap();
let prev = mem::replace(&mut disposers[i], new_disposer);
unsafe {
Expand All @@ -280,7 +270,7 @@ where
// In case the new set is shorter than the old, set the length of the mapped array.
mapped.truncate(new_items.len());

// save a copy of the mapped items for the next update.
// Save a copy of the mapped items for the next update.
items = Rc::clone(&new_items);
debug_assert!([items.len(), mapped.len(), disposers.len()]
.iter()
Expand Down
9 changes: 1 addition & 8 deletions packages/sycamore-reactive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,14 +284,7 @@ where
let boxed = Box::new(child);
let ptr = Box::into_raw(boxed);

let key = cx
.raw
.inner
.borrow_mut()
.child_scopes
// SAFETY: None of the fields of ptr are accessed through child_scopes therefore we can
// safely transmute the lifetime.
.insert(unsafe { std::mem::transmute(ptr) });
let key = cx.raw.inner.borrow_mut().child_scopes.insert(ptr);

// SAFETY: the address of the cx lives as long as 'a because:
// - It is allocated on the heap and therefore has a stable address.
Expand Down
4 changes: 2 additions & 2 deletions packages/sycamore-web/src/ssr_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ impl GenericNode for SsrNode {
let index = children
.iter()
.enumerate()
.find_map(|(i, child)| (child == reference).then(|| i))
.find_map(|(i, child)| (child == reference).then_some(i))
.expect("reference node is not a child of this node");
children.insert(index, new_node.clone());
}
Expand Down Expand Up @@ -275,7 +275,7 @@ impl GenericNode for SsrNode {
let index = children
.iter()
.enumerate()
.find_map(|(i, c)| (c == old).then(|| i))
.find_map(|(i, c)| (c == old).then_some(i))
.expect("the node to be replaced is not a child of this node");
*children[index].0.parent.borrow_mut() = Weak::new();
children[index] = new.clone();
Expand Down
10 changes: 7 additions & 3 deletions website/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![allow(deprecated)] // TODO: remove usage of deprecated API.

mod content;
mod header;
mod index;
Expand Down Expand Up @@ -71,7 +69,13 @@ fn switch<'a, G: Html>(cx: Scope<'a>, route: &'a ReadSignal<Routes>) -> View<G>
let fetch_docs_data = move |url| {
let data = create_resource(cx, docs_preload(url));
if cached_sidebar_data.get().is_none()
|| cached_sidebar_data.get().as_ref().as_ref().unwrap().0 != None
|| cached_sidebar_data
.get()
.as_ref()
.as_ref()
.unwrap()
.0
.is_some()
{
// Update sidebar
let cached_sidebar_data = cached_sidebar_data.clone();
Expand Down

0 comments on commit 75be1ca

Please sign in to comment.