#Is there a collection that both mutable, and copyable?

163 messages · Page 1 of 1 (latest)

light igloo
#

I have a struct:

#[derive(ConstDefault, Clone, Debug)]
pub struct CollectionPointer<T: 'static> {
    pub parent: Option<BuiltInPointer>,
    pub value: T,
    pub index: Option<u32>,
    /// operations done on this collection pointer.
    pub operations: ExpressionStack<T>
}

I need to implement Deref to CollectionPointer, but I can't deref to CollectionPointer unless ExpressionStack is both mutable, and copyable, but I havent been able to find a collection type that is. Ideas for what I could do?

#[derive(Deref, DerefMut, Debug, Clone, Copy)]
pub struct ExpressionStack<T>(Vec<ExpressionOperation<T>>);
ionic meadow
#

things aren't mutable, bindings are mutable

#

so your question is malformed

light igloo
ionic meadow
#
let x = 42_u32;
let mut x = x;```
#

you have a binding to a type that is not mutable, then it's made mutable

static leaf
#

there's also no way those things are necessary for Deref unless you're doing some cursed Deref hack

ionic meadow
#

yeah and that

#

what is it you want to do? also, most of those derives are not from Std, why are you using them?

light igloo
# ionic meadow what is it you want to do? also, most of those derives are not from Std, why are...

I'm trying to make the syntax for creating vecs for my library more ergonomic

/// ergonomic fragment shader
pub fn fs_main(
    input: VertexOuput
) -> impl Into<ColorBuffer> {
    return Vec4::new(input.color.x, input.color.y, input.color.z, 1.0);
}
instead of
/// ergonomic fragment shader
pub fn fs_main(
    input: VertexOuput
) -> impl Into<ColorBuffer> {
    return Vec4::new(input.color.ty.x, input.color.ty.y, input.color.ty.z, 1.0);
}

color is: Buffer<1, Vec4<F32>> which links to its inner Vec4<F32> which is in

#[derive(ConstDefault, Debug, Copy, Clone)]
pub struct Buffer<const N: u32, T> {
    /// what type the buffer is 
    pub ty: T,

    pub struc: Option<ShaderType>
}

I want to get ty's inner t without going through ty which means I need Deref. ty is CollectionPointer<T> which holds operations which I cant figure out how to implement copy so I can deref CollectionPointer<T>.

static leaf
#

It still is going to go through ty, it's just hidden from you when autoderef happens. Still not sure what copy has to do with it.

light igloo
ionic meadow
#

What does Copy have to do with this

light igloo
ionic meadow
#

Incorrect

#

Why do you believe this?

light igloo
# ionic meadow Why do you believe this?

because I'm getting this error

    return Vec4::new(input.color.x, input.color.y, input.color.z, 1.0);

cannot move out of dereference of `naga_ecs::Buffer<1, naga_ecs::wrapper_types::vec4::Vec4<naga_ecs::wrapper_types::primitives::F32>>`
move occurs because value has type `CollectionPointer<naga_ecs::wrapper_types::primitives::F32>`, which does not implement the `Copy` trait
ionic meadow
#

?play ```rust
use core::ops::Deref;

struct X(Vec<i32>);

impl Deref for X {
type Target = Vec<i32>;
fn deref(&self) -> &<Self as Deref>::Target {
&self.0
}
}```

upper capeBOT
ionic meadow
#

Vec is not Copy

static leaf
light igloo
static leaf
#

So x, y, and z are Vecs?

ionic meadow
#

but you can't do this because each of those arguments invoke the Deref impl, and you cannot do multiple partial moves through Deref

#

Only Box allows this

light igloo
# static leaf So x, y, and z are Vecs?

no, they are F32s inside of Vec4

#[derive(ConstDefault, Debug, Clone)]
pub struct Vec4<T: 'static + ConstDefault + Literal + TypeHandle + Copy + Clone> {
    pub x: CollectionPointer<T>,
    pub y: CollectionPointer<T>,
    pub z: CollectionPointer<T>,
    pub w: CollectionPointer<T>,
}
static leaf
#

What's F32?

#

They really look like CollectionPointer<T> there

light igloo
static leaf
#

Are they CollectionPointer<F32>?

light igloo
ionic meadow
#

anyway, what this F32 thing is is irrelevant. You cannot do what you want because you cannot move out of this dereference because the target is not Copy

light igloo
ionic meadow
#

but they aren't growable like a Vec is

static leaf
#

I'm guessing by mutable you meant growable?

ionic meadow
#

anyway i think you shouldn't do this

light igloo
ionic meadow
#

implementing Deref for convenience is usually a bad idea

ionic meadow
#

Deref is often invoked implicitly, so if it does weird things (which arguably your use case is), it can be really surprising to the user

static leaf
static leaf
#

So this could be input.color.with_w(1.0) or something like that

ionic meadow
#

or into_some_other_type

light igloo
static leaf
#

yea the body of that function could be that

light igloo
ionic meadow
#

i'm unconvinced that any of this is actually ergonomic

light igloo
# ionic meadow i'm unconvinced that any of this is actually ergonomic

the point of this is to replace writing shaders in wgsl with writing shaders in rust. The ergonomics match wgsl, which is the baseline im trying to match. E.G: the equivalent wgsl equivalent of the shader above

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
    return vec4<f32>(in.color.x, in.color.y, in.color.z, 1.0);
}
static leaf
#

ArrayVec is fine, but if the thing you want is Vec, you shouldn't be replacing it because of some ergonomic thing. Just looking at your function, the annoying part is having to type input.color.ty three times, so you should try to get rid of that whole thing, instead of trying to get rid of just .ty.

#

wait, what's the signature of Vec4::new?

light igloo
#

all of the intos are because it can either accept, e.g: F32, f32, or a CollectionPointer<F32>

ionic meadow
#

I'd suggest just making this an Into impl

light igloo
ionic meadow
#

it's not, but it's imo more ergonomic

light igloo
static leaf
#

Maybe this is fine but it does remove all the extra info from your CollectionPointer

#

Unless that's also saved in F32

light igloo
static leaf
#

Then you'll need to do something different for new

light igloo
ionic meadow
#

in my experience sometimes when people want to make things "ergonomic" it just turns out to be confusing and hard to debug and implicitly makes assumptions about what I want and it turns out to be a big pain

#

I think your use case is one of those

light igloo
static leaf
#

Yeah also you're competing with just two characters: (). It's hard to beat. And people already know Rust. If you do something unidiomatic it adds to the amount of stuff they need to learn.

light igloo
static leaf
#

input.x()

#

or maybe input.color.x()

light igloo
# static leaf `input.x()`
#[derive(Debug, ShaderStruct)]
pub struct VertexOuput {
    pub clip_position: PositionVertex,
    pub color: ColorBuffer
}

is what vertex output is

wgsl equivalent

struct VertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) color: vec3<f32>,
};
ionic meadow
static leaf
#

yeah but it can return a reference, which is all you need in this case

ionic meadow
#

this is a shader, i'm sure that needlessly cloning vecs is unacceptable

static leaf
#

It's not cloning the vec, it's just extracting the F32.

ionic meadow
#

sorry if that's the case, there are a lot of types here

#

but what about rust /// ergonomic fragment shader pub fn fs_main(input: VertexOuput) -> impl Into<ColorBuffer> { let SomeType{x, y, z, ..} = input.color.ty; return Vec4::new(x, y, z, 1.0); }?

#

that would be the rust-ic way of doing it

static leaf
#

Still needs .ty but at least it's just one

ionic meadow
#

uh, right

static leaf
#

Maybe this:

pub fn fs_main(input: VertexOuput) -> impl Into<ColorBuffer> {
    let [x, y, z, _] = input.into_colors();
    return Vec4::new(x, y, z, 1.0);
}
ionic meadow
#

i'm not really a fan of returning tuples for example, especially if they're the same type

#

it always feels kinda errorprone to me

static leaf
#

actually, me either lol

ionic meadow
#

Vec::into_raw_parts moment

light igloo
#

oh this is annoying, ArrayVec::new() is not const, but every method call inside of it is

    pub fn new() -> ArrayVec<T, CAP> {
        assert_capacity_limit!(CAP);
        unsafe {
            ArrayVec { xs: MaybeUninit::uninit().assume_init(), len: 0 }
        }
    }

edit: you can use new_const()

light igloo
static leaf
#

the one you're using is not this one though

#

And this one isn't going to work if you need it to be const

light igloo
# static leaf It does: <https://docs.rs/tinyvec/latest/tinyvec/struct.ArrayVec.html#impl-Copy-...

filling array out with dummy values:

#[derive(Deref, DerefMut, Debug, Clone, Copy)]
pub struct ExpressionStack(pub ArrayVec<[u8; 9999]>);
the trait `std::marker::Copy` cannot be implemented for this typerustcClick for full compiler diagnostic
lib.rs(241, 28): this field does not implement `std::marker::Copy`
lib.rs(241, 32): the `std::marker::Copy` impl for `ArrayVec<[u8; 9999]>` requires that `[u8; 9999]: tinyvec::Array
static leaf
#

It's Copy, idk why you're getting the error message

#

?play

use tinyvec::ArrayVec;

#[derive(Clone, Copy)]
pub struct ExpressionStack(pub ArrayVec<[u8; 9999]>);
upper capeBOT
inland holly
#

or &RefCell<Vec<T>> or similar

ionic meadow
#

i dont think it does

inland holly
#

it's mutable and copyable

ionic meadow
#

where does the Vec live?

inland holly
#

heap ofc

ionic meadow
#

who owns it?

inland holly
#

idc, doesn't matter

#

you can leak it

ionic meadow
#

you probably do care a lot about leaking

#

especially your users

light igloo
static leaf
#

nooooooooooooo

ionic meadow
drowsy jetty
#

I don't think it's been mentioned here yet, what about using Into instead of Deref? If you take an Into<the thing>, won't it work the same, but without the hassle?

static leaf
#

You'd need to make x, y, and z different types to get the right fields into the right parameters

#

still can't move them tho

inland holly
#

I think there's only two correct answers to the question as posed:

  • a value type, where the entire collection gets copied
  • pointer type, where the collection doesn't get copied
    since you can't copy mutable references, it would have to be an immutable reference with interior mutability
light igloo
ionic meadow
light igloo
ionic meadow
#

yup

#

its probably alright if you do it once, but definitely not if you do it a lot

light igloo
light igloo
inland holly
#

uhhh

#

honestly, I jsut said this to answer your original question

#

you could do it this way, but it's probably not the right way to do it

ionic meadow
#

could you even implement Deref if you have to go through the refcell?

inland holly
#

I think you can

#

well

#

kinda maybe not really?

static leaf
#

Anyway this doesn't matter because by mutable they just meant growable. ArrayVec does it. You don't need to deref through the refcell because that's not the target of the deref

light igloo
static leaf
#

Idk, the error you showed doesn't make sense with the code you posted.

light igloo
# static leaf Idk, the error you showed doesn't make sense with the code you posted.

given, say, the below sample code:

#[derive(Clone, Copy)]
pub struct TestArrayVec(ArrayVec<[u32; 9999]>);

how do you make it so ArrayVec allows Copy for [u32; 9999]? Because currently, this is the error the sample code will give you

error[E0204]: the trait `Copy` cannot be implemented for this type
  --> src/main.rs:26:17
   |
26 | #[derive(Clone, Copy)]
   |                 ^^^^
27 | pub struct TestArrayVec(ArrayVec<[u32; 9999]>);
   |                         --------------------- this field does not implement `Copy`
   |
note: the `Copy` impl for `ArrayVec<[u32; 9999]>` requires that `[u32; 9999]: Array`
  --> src/main.rs:27:25
   |
27 | pub struct TestArrayVec(ArrayVec<[u32; 9999]>);
   |                         ^^^^^^^^^^^^^^^^^^^^^
   = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
static leaf
light igloo
ionic meadow
#

?play ```rust
use tinyvec::ArrayVec;

#[derive(Clone, Copy)]
pub struct TestArrayVec(ArrayVec<[u32; 9999]>);```

upper capeBOT
#
The operation timed out: deadline has elapsed```
static leaf
#

rip playground :(

ionic meadow
#

you could have avoided all of this by just typing a few extra words in your fs main

#

i wouldnt use arrayvec for this tbh. especially if the buffer is big

light igloo
static leaf
#

what limit?

light igloo
ionic meadow
#

and this type is pretty big

#

i wouldnt want to be copying it around

static leaf
#

Yeah usually you use ArrayVec with like 10

light igloo
static leaf
#

It's supposed to be used with small things

ionic meadow
#

do you understand what having a big arrayvec means?

ionic meadow
#

it means that whenever it's moved, the entire thing is copied

#

if you move a vec, only the vec struct is moved, not the buffer

#

this is why you only really see people use arrayvec for small things

light igloo
#

hm.. Mabye my problem is my approach. keeping the expressions done on the expression them self is very convienient, but this seems like it would get
exponentially more expensive the more operations that are added to CollectionPointer...

#

I think I'll just take the ergonomics hit for needing .ty. to avoid the copy until I get this into a MVP state. Doing this correctly seems like Its going to take more time then its worth at the moment.

ionic meadow
#

or rust /// ergonomic fragment shader pub fn fs_main(input: VertexOuput) -> impl Into<ColorBuffer> { let SomeType{x, y, z, ..} = input.color.ty; return Vec4::new(x, y, z, 1.0); }

ionic meadow
#

Whatever type your .ty field is

static leaf
#

It would be input.color.ty.value

#

and then it gets destructured into Vec4 { x, y, z, .. }

light igloo
static leaf
#

oh

#

Okay then just Vec4