Skip to content

Commit

Permalink
Add option for rust generator for custom str implementations for types (
Browse files Browse the repository at this point in the history
  • Loading branch information
leighmcculloch authored Oct 24, 2023
1 parent b405294 commit 64612a2
Show file tree
Hide file tree
Showing 17 changed files with 23,603 additions and 41 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ The command line:

`xdrgen [-o OUTPUT_DIR] [-l LANGUAGE] [-n NAMESPACE] [INPUT_FILES ...]`

### Language Specific Options

### Rust

`--rust-types-custom-str-impl`: Used to specify a comma-separated list of type names that should not have string conversion code generated as it will be provided by custom implementations provided by the developer using the generated code.

## Usage as a library

Add this line to your application's Gemfile:
Expand All @@ -63,7 +69,10 @@ c = Xdrgen::Compilation.new(
["MyProgram.x"],
output_dir:"src/generated",
language: :ruby,
namespace: "MyProgram::XDR"
namespace: "MyProgram::XDR",
options: {
rust_types_custom_str_impl: [],
},
)

# then run compile
Expand Down
6 changes: 5 additions & 1 deletion lib/xdrgen/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def self.run(args)
on 'o', 'output=', 'The output directory'
on 'l', 'language=', 'The output language', default: 'ruby'
on 'n', 'namespace=', '"namespace" to generate code within (language-specific)'
on 'rust-types-custom-str-impl=', 'Rust types that should not have str implementations generated as they will be provided via custom implementations (rust-specific)'
end

fail(opts) if args.blank?
Expand All @@ -18,7 +19,10 @@ def self.run(args)
args,
output_dir: opts[:output],
language: opts[:language].to_sym,
namespace: opts[:namespace]
namespace: opts[:namespace],
options: {
rust_types_custom_str_impl: opts[:"rust-types-custom-str-impl"]&.split(',') || [],
},
)
compilation.compile
end
Expand Down
7 changes: 4 additions & 3 deletions lib/xdrgen/compilation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ module Xdrgen
class Compilation
extend Memoist

def initialize(source_paths, output_dir:".", language: :ruby, namespace: nil)
def initialize(source_paths, output_dir:".", language: :ruby, namespace: nil, options: {})
@source_paths = source_paths
@output_dir = output_dir
@namespace = namespace
@language = language
@options = options
end

memoize def source
Expand All @@ -22,10 +23,10 @@ def compile
output = Output.new(@source_paths, @output_dir)


generator = Generators.for_language(@language).new(ast, output, @namespace)
generator = Generators.for_language(@language).new(ast, output, @namespace, @options)
generator.generate
ensure
output.close
end
end
end
end
5 changes: 3 additions & 2 deletions lib/xdrgen/generators/base.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
class Xdrgen::Generators::Base
def initialize(top, output, namespace=nil)
def initialize(top, output, namespace=nil, options={})
@top = top
@output = output
@namespace = namespace
@options = options
end

def generate
raise NotImplementedError
end
end
end
41 changes: 29 additions & 12 deletions lib/xdrgen/generators/rust.rb
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,11 @@ def render_source_comment(out, defn)
def render_struct(out, struct)
out.puts "#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]"
out.puts %{#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]}
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]}
if @options[:rust_types_custom_str_impl].include?(name struct)
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr))]}
else
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]}
end
out.puts "pub struct #{name struct} {"
out.indent do
struct.members.each do |m|
Expand Down Expand Up @@ -404,7 +408,11 @@ def render_enum(out, enum)
out.puts "// enum"
out.puts "#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]"
out.puts %{#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]}
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]}
if @options[:rust_types_custom_str_impl].include?(name enum)
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr))]}
else
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]}
end
out.puts "#[repr(i32)]"
out.puts "pub enum #{name enum} {"
out.indent do
Expand Down Expand Up @@ -529,7 +537,11 @@ def render_union(out, union)
out.puts "// union with discriminant #{discriminant_type}"
out.puts "#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]"
out.puts %{#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]}
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]}
if @options[:rust_types_custom_str_impl].include?(name union)
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr))]}
else
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]}
end
out.puts "#[allow(clippy::large_enum_variant)]"
out.puts "pub enum #{name union} {"
union_case_count = 0
Expand Down Expand Up @@ -659,34 +671,39 @@ def render_typedef(out, typedef)
out.puts "#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]"
out.puts %{#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]}
out.puts "#[derive(Default)]" if is_var_array_type(typedef.type)
if is_fixed_array_opaque(typedef.type)
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr))]}
if is_fixed_array_opaque(typedef.type) || @options[:rust_types_custom_str_impl].include?(name typedef)
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr))]}
else
out.puts "#[derive(Debug)]"
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]}
out.puts %{#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]}
end
if !is_fixed_array_opaque(typedef.type)
out.puts "#[derive(Debug)]"
end
out.puts "pub struct #{name typedef}(pub #{reference(typedef, typedef.type)});"
out.puts ""
if is_fixed_array_opaque(typedef.type)
out.puts <<-EOS.strip_heredoc
impl core::fmt::Display for #{name typedef} {
impl core::fmt::Debug for #{name typedef} {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let v = &self.0;
write!(f, "#{name typedef}(")?;
for b in v {
write!(f, "{b:02x}")?;
}
write!(f, ")")?;
Ok(())
}
}
impl core::fmt::Debug for #{name typedef} {
EOS
end
if is_fixed_array_opaque(typedef.type) && !@options[:rust_types_custom_str_impl].include?(name typedef)
out.puts <<-EOS.strip_heredoc
impl core::fmt::Display for #{name typedef} {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let v = &self.0;
write!(f, "#{name typedef}(")?;
for b in v {
write!(f, "{b:02x}")?;
}
write!(f, ")")?;
Ok(())
}
}
Expand Down
4 changes: 2 additions & 2 deletions spec/lib/xdrgen/generator_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'spec_helper'

describe Xdrgen::Generators do
languages = %w(ruby javascript go java elixir rust)
languages = %w(ruby javascript go java elixir)
focus_language = "" #"go"
focus_basename = "" #"optional.x"

Expand All @@ -22,7 +22,7 @@ def generate(language, path)
[path],
output_dir: "#{SPEC_ROOT}/output/generator_spec_#{language}/#{File.basename path}",
language: language,
namespace: "MyXDR"
namespace: "MyXDR",
)
compilation.compile
compilation
Expand Down
36 changes: 36 additions & 0 deletions spec/lib/xdrgen/rust_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require 'spec_helper'

describe Xdrgen::Generators::Rust do
generator_fixture_paths.each do |path|
it "can generate #{File.basename path}" do
c = generate path, ""
end

it "can generate #{File.basename path} with custom str impls" do
c = generate path, "_custom_str_impls", {
rust_types_custom_str_impl: [
"Foo",
"TestArray",
"Color2",
"UnionKey",
"MyUnion",
"HasOptions",
"MyStruct",
"LotsOfMyStructs",
],
}
end
end

def generate(path, output_sub_path, options = {rust_types_custom_str_impl: []})
compilation = Xdrgen::Compilation.new(
[path],
output_dir: "#{SPEC_ROOT}/output/generator_spec_rust#{output_sub_path}/#{File.basename path}",
language: "rust",
namespace: "MyXDR",
options: options,
)
compilation.compile
compilation
end
end
36 changes: 17 additions & 19 deletions spec/output/generator_spec_rust/test.x/MyXDR.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2305,24 +2305,23 @@ mod test {
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr))]
pub struct Uint512(pub [u8; 64]);

impl core::fmt::Display for Uint512 {
impl core::fmt::Debug for Uint512 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let v = &self.0;
write!(f, "Uint512(")?;
for b in v {
write!(f, "{b:02x}")?;
}
write!(f, ")")?;
Ok(())
}
}

impl core::fmt::Debug for Uint512 {
impl core::fmt::Display for Uint512 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let v = &self.0;
write!(f, "Uint512(")?;
for b in v {
write!(f, "{b:02x}")?;
}
write!(f, ")")?;
Ok(())
}
}
Expand Down Expand Up @@ -2417,8 +2416,8 @@ impl AsRef<[u8]> for Uint512 {
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Default)]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct Uint513(pub BytesM::<64>);

impl From<Uint513> for BytesM::<64> {
Expand Down Expand Up @@ -2516,8 +2515,8 @@ impl AsRef<[u8]> for Uint513 {
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Default)]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct Uint514(pub BytesM);

impl From<Uint514> for BytesM {
Expand Down Expand Up @@ -2615,8 +2614,8 @@ impl AsRef<[u8]> for Uint514 {
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Default)]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct Str(pub StringM::<64>);

impl From<Str> for StringM::<64> {
Expand Down Expand Up @@ -2714,8 +2713,8 @@ impl AsRef<[u8]> for Str {
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Default)]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct Str2(pub StringM);

impl From<Str2> for StringM {
Expand Down Expand Up @@ -2815,24 +2814,23 @@ impl AsRef<[u8]> for Str2 {
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde_with::SerializeDisplay, serde_with::DeserializeFromStr))]
pub struct Hash(pub [u8; 32]);

impl core::fmt::Display for Hash {
impl core::fmt::Debug for Hash {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let v = &self.0;
write!(f, "Hash(")?;
for b in v {
write!(f, "{b:02x}")?;
}
write!(f, ")")?;
Ok(())
}
}

impl core::fmt::Debug for Hash {
impl core::fmt::Display for Hash {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let v = &self.0;
write!(f, "Hash(")?;
for b in v {
write!(f, "{b:02x}")?;
}
write!(f, ")")?;
Ok(())
}
}
Expand Down Expand Up @@ -2926,8 +2924,8 @@ impl AsRef<[u8]> for Hash {
//
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct Hashes1(pub [Hash; 12]);

impl From<Hashes1> for [Hash; 12] {
Expand Down Expand Up @@ -3013,8 +3011,8 @@ impl AsRef<[Hash]> for Hashes1 {
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Default)]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct Hashes2(pub VecM::<Hash, 12>);

impl From<Hashes2> for VecM::<Hash, 12> {
Expand Down Expand Up @@ -3112,8 +3110,8 @@ impl AsRef<[Hash]> for Hashes2 {
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Default)]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct Hashes3(pub VecM::<Hash>);

impl From<Hashes3> for VecM::<Hash> {
Expand Down Expand Up @@ -3210,8 +3208,8 @@ impl AsRef<[Hash]> for Hashes3 {
//
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct OptHash1(pub Option<Hash>);

impl From<OptHash1> for Option<Hash> {
Expand Down Expand Up @@ -3259,8 +3257,8 @@ impl WriteXdr for OptHash1 {
//
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct OptHash2(pub Option<Hash>);

impl From<OptHash2> for Option<Hash> {
Expand Down
2 changes: 1 addition & 1 deletion spec/output/generator_spec_rust/union.x/MyXDR.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2631,8 +2631,8 @@ Self::V1(v) => v.write_xdr(w)?,
//
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Debug)]
#[cfg_attr(all(feature = "serde", feature = "alloc"), derive(serde::Serialize, serde::Deserialize), serde(rename_all = "snake_case"))]
#[derive(Debug)]
pub struct IntUnion2(pub IntUnion);

impl From<IntUnion2> for IntUnion {
Expand Down
Loading

0 comments on commit 64612a2

Please sign in to comment.