Compare commits

..

2 Commits

Author SHA1 Message Date
Daan Vanoverloop a0a3ebb856
Lifetime subtyping and variance??? 2022-09-09 20:19:18 +02:00
Daan Vanoverloop 30d96df00a
Temp 2022-09-09 16:55:30 +02:00
4 changed files with 181 additions and 39 deletions

6
web/dist/index.html vendored
View File

@ -6,7 +6,7 @@
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@6.9.96/css/materialdesignicons.min.css" rel="stylesheet">
<title>LAN Party</title>
<link rel="preload" href="/index-fd3fb1b7ad6689f9_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
<link rel="modulepreload" href="/index-fd3fb1b7ad6689f9.js"></head>
<link rel="preload" href="/index-175ab564dbb350a3_bg.wasm" as="fetch" type="application/wasm" crossorigin="">
<link rel="modulepreload" href="/index-175ab564dbb350a3.js"></head>
<body>
<script type="module">import init from '/index-fd3fb1b7ad6689f9.js';init('/index-fd3fb1b7ad6689f9_bg.wasm');</script></body></html>
<script type="module">import init from '/index-175ab564dbb350a3.js';init('/index-175ab564dbb350a3_bg.wasm');</script></body></html>

View File

@ -1,4 +1,4 @@
use std::str::FromStr;
use std::{cell::RefCell, marker::PhantomData, str::FromStr};
use crate::components::Block;
use lan_party_core::event::{
@ -7,11 +7,11 @@ use lan_party_core::event::{
};
use log::debug;
use paste::paste;
use sycamore::prelude::*;
use sycamore::{builder::prelude::*, component::Prop, prelude::*};
macro_rules! editable {
($type:ty => $editor:ty) => {
impl<'a, G: Html> Editable<'a, G> for $type {
impl<'s: 'a, 'a, G: Html> Editable<'s, 'a, G> for $type {
type Editor = $editor;
}
};
@ -32,7 +32,7 @@ macro_rules! edit_fields {
macro_rules! link_fields {
($cx:ident, $($field:ident),* $(,)? => $state:ident as $t:ident) => {
$(let $field = create_signal($cx, $state.get().$field.clone());)*
$(let $field = create_signal($cx, $state.get_untracked().$field.clone());)*
create_effect($cx, || {
$state.set($t {
@ -48,7 +48,7 @@ macro_rules! edit_struct {
paste! {
pub struct [<$struct Edit>];
impl<'a, G: Html> Editor<'a, G, $struct> for [<$struct Edit>] {
impl<'s: 'a, 'a, G: Html> Editor<'s, 'a, G, $struct> for [<$struct Edit>] {
fn edit(cx: Scope<'a>, props: EditProps<'a, $struct>) -> View<G> {
let state = props.state;
link_fields!(cx, $($prop,)* => state as $struct);
@ -69,7 +69,7 @@ macro_rules! link_variants {
($cx:ident, $selected:ident => $($index:literal: $var_name:ident = $variant:ident: $var_type:ty),* $(,)? => $state:ident as $t:ident) => {
let $selected = create_signal($cx, String::from("0"));
$(let $var_name = if let $t::$variant(v) = $state.get().as_ref().clone() {
$(let $var_name = if let $t::$variant(v) = $state.get_untracked().as_ref().clone() {
create_signal($cx, v.clone())
} else {
create_signal($cx, <$var_type>::default())
@ -90,7 +90,7 @@ macro_rules! edit_enum {
paste! {
pub struct [<$enum Edit>];
impl<'a, G: Html> Editor<'a, G, $enum> for [<$enum Edit>] {
impl<'s: 'a, 'a, G: Html> Editor<'s, 'a, G, $enum> for [<$enum Edit>] {
fn edit(cx: Scope<'a>, props: EditProps<'a, $enum>) -> View<G> {
let state = props.state;
@ -104,8 +104,9 @@ macro_rules! edit_enum {
select(bind:value=$selected) {
$(option(value={stringify!($index)}, selected=$index==0) { (stringify!($variant)) })*
}
(match state.get().as_ref().clone() {
$($enum::$variant(_) => $var_name.edit(cx),)*
(match $selected.get().as_str() {
$(stringify!($index) => $var_name.edit(cx),)*
_ => unreachable!()
})
}
}
@ -128,35 +129,40 @@ impl<'a, T> From<&'a Signal<T>> for EditProps<'a, T> {
}
}
pub trait IntoEdit<'a, G: Html> {
fn edit(self, cx: Scope<'a>) -> View<G>;
pub trait IntoEdit<'s: 'a, 'a, G: Html> {
fn edit(self, cx: BoundedScope<'a, 's>) -> View<G>;
}
impl<'a, G: Html, T: Editable<'a, G>> IntoEdit<'a, G> for &'a Signal<T>
impl<'s: 'a, 'a, G: Html, T: Editable<'s, 'a, G> + 'a> IntoEdit<'s, 'a, G> for &'a Signal<T>
where
EditProps<'a, T>: From<&'a Signal<T>>,
{
fn edit(self, cx: Scope<'a>) -> View<G> {
fn edit(self, cx: BoundedScope<'a, 's>) -> View<G> {
T::edit(cx, self.into())
}
}
pub trait Edit<'a, G: Html>: Sized {
fn edit(cx: Scope<'a>, props: EditProps<'a, Self>) -> View<G>;
pub trait Edit<'s: 'a, 'a, G: Html>: Sized {
fn edit(cx: BoundedScope<'a, 's>, props: EditProps<'a, Self>) -> View<G>;
}
impl<'a, G: Html, E: Editor<'a, G, Type>, Type: Editable<'a, G, Editor = E>> Edit<'a, G> for Type {
fn edit(cx: Scope<'a>, props: EditProps<'a, Self>) -> View<G> {
impl<'s: 'a, 'a, G, E, Type> Edit<'s, 'a, G> for Type
where
G: Html,
E: Editor<'s, 'a, G, Type>,
Type: Editable<'s, 'a, G, Editor = E> + 'a,
{
fn edit(cx: BoundedScope<'a, 's>, props: EditProps<'a, Self>) -> View<G> {
E::edit(cx, props)
}
}
pub trait Editor<'a, G: Html, Type>: Sized {
fn edit(cx: Scope<'a>, props: EditProps<'a, Type>) -> View<G>;
pub trait Editor<'s: 'a, 'a, G: Html, Type: 'a>: Sized {
fn edit(cx: BoundedScope<'a, 's>, props: EditProps<'a, Type>) -> View<G>;
}
pub trait Editable<'a, G: Html>: Sized {
type Editor: Editor<'a, G, Self>;
pub trait Editable<'s: 'a, 'a, G: Html>: Sized + 'a {
type Editor: Editor<'s, 'a, G, Self>;
}
edit_struct!(EventSpec => ("Name", name), ("Description", description), ("Event type", event_type));
@ -168,12 +174,12 @@ edit_enum!(EventTypeSpec => selected =>
);
edit_struct!(TestSpec => ("Number of players", num_players));
edit_struct!(TeamGameSpec => );
edit_struct!(TeamGameSpec => ("Win rewards", win_rewards));
edit_struct!(FreeForAllGameSpec => );
pub struct StringEdit;
impl<'a, G: Html> Editor<'a, G, String> for StringEdit {
impl<'s: 'a, 'a, G: Html> Editor<'s, 'a, G, String> for StringEdit {
fn edit(cx: Scope<'a>, props: EditProps<'a, String>) -> View<G> {
view! { cx,
input(bind:value=props.state)
@ -185,9 +191,9 @@ editable!(String => StringEdit);
pub struct StubEdit;
impl<'a, G: Html, T> Editor<'a, G, T> for StubEdit
impl<'s: 'a, 'a, G: Html, T> Editor<'s, 'a, G, T> for StubEdit
where
T: Editable<'a, G, Editor = StubEdit>,
T: Editable<'s, 'a, G, Editor = StubEdit>,
{
fn edit(cx: Scope<'a>, _props: EditProps<'a, T>) -> View<G> {
view! { cx,
@ -196,16 +202,14 @@ where
}
}
//editable!(EventTypeSpec => StubEdit);
pub struct InputEdit;
impl<'a, G: Html, T> Editor<'a, G, T> for InputEdit
impl<'s: 'a, 'a, G: Html, T> Editor<'s, 'a, G, T> for InputEdit
where
T: Editable<'a, G, Editor = InputEdit> + FromStr + ToString + Default,
T: Editable<'s, 'a, G, Editor = InputEdit> + FromStr + ToString + Default,
{
fn edit(cx: Scope<'a>, props: EditProps<'a, T>) -> View<G> {
let value = create_signal(cx, props.state.get().to_string());
let value = create_signal(cx, props.state.get_untracked().to_string());
create_effect(cx, || {
props
@ -232,7 +236,7 @@ editable!(f32 => InputEdit);
pub struct BoolEdit;
impl<'a, G: Html> Editor<'a, G, bool> for BoolEdit {
impl<'s: 'a, 'a, G: Html> Editor<'s, 'a, G, bool> for BoolEdit {
fn edit(cx: Scope<'a>, props: EditProps<'a, bool>) -> View<G> {
view! { cx,
input(type="checkbox", bind:checked=props.state)
@ -242,7 +246,145 @@ impl<'a, G: Html> Editor<'a, G, bool> for BoolEdit {
editable!(bool => BoolEdit);
#[derive(Default, Clone)]
pub struct VecEdit;
impl<'s: 'a, 'a, G, T, I> Editor<'s, 'a, G, I> for VecEdit
where
G: Html,
T: Editable<'s, 'a, G> + Clone + PartialEq + 'a,
I: IntoIterator<Item = T> + FromIterator<T> + Clone + 'a,
{
fn edit(cx: BoundedScope<'a, 's>, props: EditProps<'a, I>) -> View<G> {
let vec: &'a Signal<Vec<&'a Signal<T>>> = create_signal(
cx,
props
.state
.get_untracked()
.as_ref()
.clone()
.into_iter()
.map(|x| create_signal(cx, x))
.collect::<Vec<_>>(),
);
//let signal = create_signal(cx, 0);
//let vec2 = vec.get().as_ref().clone();
//let signal = create_ref(cx, vec.get(0).unwrap());
create_effect(cx, || {
props.state.set(
vec.get()
.iter()
.cloned()
.map(|x| x.get().as_ref().clone())
.collect(),
)
});
let test = Indexed(
cx,
IndexedProps::builder()
.iterable(vec)
.view(|cx: BoundedScope<'_, '_>, x: &'a Signal<T>| {
//view! { cx, (T::edit(cx, EditProps { state: x })) }
T::edit(cx, EditProps { state: x })
})
.build(),
);
test
/*
//view! { cx, "Vec" }
view! { cx,
Indexed(
iterable=vec,
view=|cx: BoundedScope<'_, 'a>, x: &'a Signal<T>| {
view! { cx,
//(T::edit(cx, EditProps { state: x }))
(something_with_signal(cx, EditProps { state: x }))
}
},
)
}
*/
/*
view! { cx,
(View::new_fragment((vec.get().try_borrow().unwrap().clone().into_iter().map(|s: &'a Signal<T>| {
view! { cx, (T::edit(cx, s.into())) }
})).collect()))
}
*/
}
}
/*
#[component]
pub fn VecTest<
'a,
G: Html,
T: 'a + PartialEq + Clone + Editable<'a, G, Editor = E>,
E: Editor<'a, G, T>,
>(
cx: Scope<'a>,
props: EditProps<'a, Vec<T>>,
) -> View<G> {
/*
let signals: &'a Signal<Vec<&'a Signal<String>>> = create_signal(
cx,
vec![
create_signal(cx, String::new()),
create_signal(cx, String::new()),
],
);
*/
let signals = create_signal(
cx,
props
.state
.get()
.iter()
.cloned()
.map(|s| create_signal(cx, s))
.collect::<Vec<_>>(),
);
view! { cx,
Indexed(
iterable=signals,
view=|cx: BoundedScope<'_, 'a>, signal: &'a Signal<T>| {
view! { cx,
//(something_with_signal(cx, SignalWrapper(signal)))
//(E::edit(cx, EditProps { state: signal }))
//(T::edit(cx, EditProps { state: signal }))
//(signal.edit(cx))
}
},
)
}
}
*/
pub struct SignalWrapper<'a, T>(&'a Signal<T>);
#[component]
pub fn something_with_signal<'a, G: Html, T: 'a>(
cx: Scope<'a>,
signal: EditProps<'a, T>,
) -> View<G> {
drop(signal);
view! { cx, "Something" }
}
impl<'s: 'a, 'a, G, T> Editable<'s, 'a, G> for Vec<T>
where
G: Html,
T: Editable<'s, 'a, G> + Clone + PartialEq + 'a,
{
type Editor = VecEdit;
}
#[derive(Default, Clone, Debug)]
pub struct Test {
inner: TestInner,
inner2: TestInner,
@ -250,7 +392,7 @@ pub struct Test {
edit_struct!(Test => ("Inner", inner), ("Inner 2", inner2));
#[derive(Default, Clone)]
#[derive(Default, Clone, Debug)]
pub struct TestInner {
some_text: String,
some_number: usize,

View File

@ -1,7 +1,9 @@
pub mod event;
use log::debug;
use sycamore::prelude::*;
use web_sys::Event;
use yew::use_effect;
#[derive(Prop)]
pub struct Props<F: FnMut(Event)> {

View File

@ -11,13 +11,11 @@ use crate::components::{
#[component]
pub fn EventsPage<'a, G: Html>(cx: Scope<'a>) -> View<G> {
let event_spec = create_signal(cx, EventSpec::default());
let test = create_signal(cx, Test::default());
view! { cx,
Block(title="Create new event".into()) {
EventSpec::edit(EditProps { state: event_spec })
(event_spec.edit(cx))
Button(icon="mdi-check".into(), onclick=move |_| debug!("{:#?}", event_spec.get()))
(test.edit(cx))
}
}
}