Skip to content

[Bug] documentation / functionality to generate correct c++ code for generics when using serde-name #37

@johnperry-math

Description

@johnperry-math

🐛 Bug

If you need to generate C++ code for a generic, documentation needs more information on how to obtain correct code, or serde-generate needs to generate valid code for C++ generics when using recommended procedure

To reproduce

Extended from the example in serde-name, recommended in serde-reflection docs.

use std::path::PathBuf;

use serde::{Deserialize, Serialize};
use serde_generate::SourceInstaller;
use serde_name::{DeserializeNameAdapter, SerializeNameAdapter};
use serde_reflection::{FormatHolder, Samples, Tracer, TracerConfig};

#[derive(Serialize, Deserialize)]
#[serde(remote = "Foo")] // Generates Foo::(de)serialize instead of implementing Serde traits.
struct Foo<T> {
    data: T,
}

impl<'de, T> Deserialize<'de> for Foo<T>
where
    T: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>,
    {
        Foo::deserialize(DeserializeNameAdapter::new(
            deserializer,
            std::any::type_name::<Self>(),
        ))
    }
}

impl<T> Serialize for Foo<T>
where
    T: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        Foo::serialize(
            self,
            SerializeNameAdapter::new(serializer, std::any::type_name::<Self>()),
        )
    }
}

fn main() {
    // Testing the Deserialize implementation
    assert!(serde_name::trace_name::<Foo<u64>>()
        .unwrap()
        .ends_with("Foo<u64>"));

    // Testing the Serialize implementation
    use serde_reflection::*;
    let mut tracer = Tracer::new(TracerConfig::default());
    let mut samples = Samples::new();
    let (mut ident, _) = tracer
        .trace_value(&mut samples, &Foo { data: 1u64 })
        .unwrap();
    ident.normalize().unwrap();
    assert!(matches!(ident, Format::TypeName(s) if s.ends_with("Foo<u64>")));
    let registry = tracer.registry().unwrap();
    let config = serde_generate::CodeGeneratorConfig::new("generic_to_cpp".to_string())
        .with_encodings(vec![serde_generate::Encoding::Bincode]);
    let installer = serde_generate::cpp::Installer::new(PathBuf::from("a_new_lib"));
    installer.install_module(&config, &registry).unwrap();
    installer.install_bincode_runtime().unwrap();
    installer.install_serde_runtime().unwrap();
}

Generated C++ code

#pragma once

#include "serde.hpp"
#include "bincode.hpp"

namespace generic_to_cpp {

    struct generic_to_cpp::Foo<u64> {
        uint64_t data;
// and more like this

😢

Expected C++ code

  • ideally, something like
#include "serde.hpp"
#include "bincode.hpp"

namespace generic_to_cpp {

    template <typename T>
    struct Foo{
        T data;
// etc.
}
  • Otherwise, an example that shows how to build on the example in serde-name to obtain valid C++ code for the instantiated type.

System information

Please complete the following information:

  • Serde Reflection version 0.3.6
  • Rust version 1.74.0

Additional context

I've also tried this at least with trace_type.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions