Serde a struct array

I have an array, each element is a struct, I have do something for the struct G1, according to https://serde.rs/remote-derive.html this tutorial. but I got an array when I want to use it for [G1,L].
image
The ECPDef seems work for G1 struct, but not work for [G1,L], can you help me, plz

Function specified for serde(with is for a specific type, you can't change its type.

Try this instead:

#[repr(transparent)]
struct G1Wrapper(#[serde(with = "ECPDef")] G1);

and then

c: [G1Wrapper; L]

you can transmute between [G1Wrapper; L] and [G1; L] if you have to.

Another option would be to write your own function for serde(with that supports arrays.

thanks for your replay but still some error
image
image
image

The SipCipher is a remote struct, it's filed c is [G1;L], if change to [G1Wrapper; L] is that ok? Or there are some other reason

Serde unfortunately does not support generics of arbitrary length; they decided at some point to support [T; 0]: Serialize without a T: Serialize bound (and the same for Deserialize) which prevents creating a generic implementation in a backwards compatible way, at least with the current capabilities of rust. (The standard library has the same problem with [T; N]: Default, so it seems likely that there will be a fix eventually, but it could take years still.)

For now, you'll need to "manually" handle the array, possibly using another crate. For example with

serde_with - Rust

you could use something like

#[serde_as(as = "[FromInto<G1Wrapper>; L]")] 
c: [G1; L] 

(haven't tested the code)

and even save the need for transmutes, too. (You need to implement From<G1Wrapper> for G1 and From<G1> for G1Wrapper for this, or alternatively the corresponding Into implementations. You could also use derive_more for From and Into on GTWrapper if you don't want to write any implementations manually.)

Edit: Actually, the use of FromInto would introduce an additional Clone when serializing. If cloning G1 is too much overhead, using the G1Wrapper with transmute as suggested before might be the better option. You can do

#[serde_as(as = "[_; L]")] 
c: [G1Wrapper; L] 

(haven't tested the code)

to handle the array.

1 Like

I want to convert this SipCipher struct defined in https://github.com/Ruby-Protocol/private_ml/blob/main/src/simple_ip.rs which look like
#[derive(Debug)] pub struct SipCipher<const L: usize> { c0: G1, c: [G1; L] }
the G1 is actually a struct called ECP defined in https://github.com/lovesh/miracl_core_generated/blob/master/rust_64/src/bls12381/ecp.rs
So I followed the serde doc https://serde.rs/remote-derive.html to add ECPDef for use in SipCipher.
So now the code will look like #[derive(Serialize,Deserialize)] pub struct SipCipher<const L: usize> { #[serde(with="ECPDef")] c0: G1, #[serde(with="ECPDef")] c: [G1; L] }
but some thing wrong
image

"mismatched types

expected struct miracl_core::bls12381::ecp::ECP, found array

note: expected reference &miracl_core::bls12381::ecp::ECP
found reference &'__a [miracl_core::bls12381::ecp::ECP; L]rustc(E0308)
simple_ip.rs(49, 10): expected struct miracl_core::bls12381::ecp::ECP, found array"

So can anyone help me? PLZ

Thank you so much for the replay. If I want to remain c:[G1;L], what should I do. I already implement From<G1Wrapper> for G1 and From<G1> for G1Wrapper. but some new error
cannot find type FromInto in this scope not found in this scoperustc(E0412)
image

You need to: use serde_with::FromInto; :wink:

thank you so much, you are so nice!!!!

I just noticed that ECPDef is probably also remote derived... you can save the unnecessary clone on serialization by following this pattern

https://docs.rs/serde_with/1.11.0/serde_with/guide/serde_as/index.html#using-serde_as-with-serdes-remote-derives

It's probably also more concise, you don't need to define a wrapper type at all. Just implement the necessary trivial impl<'de> DeserializeAs<'de, G1> for ECPDef and SerializeAs<G1> for ECPDef and the you can use (as = "[ECPDef; L]") on an [G1; L] field.

1 Like

:worried: I am sorry, but I just find out the remote struct ECP impls tostring(). which means the pub struct SipCipher<const L: usize> { c0: G1, c: [G1; L] } can be directly into some string like this

impl<const L: usize> SipCipher<L>{

fn getc0(&self) -> String {
    self.c0.tostring()
}

fn getc(&self) -> Vec<String>{
    let result: Vec<String> = self.c.iter().map(|g| g.tostring()).collect();
    result
}}

then I need JSON those string

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.