reflect: hide spirv details from consumer

This commit is contained in:
chyyran 2022-11-09 01:51:10 -05:00
parent 301b8bf209
commit 993359115e
10 changed files with 196 additions and 144 deletions

2
Cargo.lock generated
View file

@ -448,7 +448,6 @@ dependencies = [
"librashader-presets", "librashader-presets",
"librashader-reflect", "librashader-reflect",
"rustc-hash", "rustc-hash",
"spirv_cross",
"windows", "windows",
] ]
@ -461,7 +460,6 @@ dependencies = [
"librashader-presets", "librashader-presets",
"librashader-reflect", "librashader-reflect",
"rustc-hash", "rustc-hash",
"spirv_cross",
"windows", "windows",
] ]

View file

@ -2,4 +2,3 @@ use crate::back::ShaderCompiler;
use crate::back::targets::GLSL; use crate::back::targets::GLSL;
use crate::error::ShaderCompileError; use crate::error::ShaderCompileError;
use crate::reflect::ShaderReflection; use crate::reflect::ShaderReflection;

View file

@ -10,3 +10,4 @@ pub struct CompiledShader<Source, Context = ()> {
pub fragment: Source, pub fragment: Source,
pub context: Context, pub context: Context,
} }

View file

@ -1,11 +1,13 @@
use crate::back::CompiledShader; use crate::back::CompiledShader;
use crate::error::ShaderCompileError; use crate::error::{ShaderCompileError, ShaderReflectError};
use crate::reflect::ShaderReflection; use crate::front::shaderc::GlslangCompilation;
use crate::reflect::{ReflectSemantics, ReflectShader, ShaderReflection};
use crate::reflect::cross::{GlslReflect, HlslReflect};
pub trait OutputTarget { } pub trait OutputTarget { }
pub struct GLSL; pub struct GLSL(GlslReflect);
pub struct HLSL; pub struct HLSL(HlslReflect);
pub struct SpirV; pub struct SpirV;
pub struct MSL; pub struct MSL;
@ -14,10 +16,55 @@ impl OutputTarget for HLSL {}
impl OutputTarget for SpirV {} impl OutputTarget for SpirV {}
impl OutputTarget for MSL {} impl OutputTarget for MSL {}
pub trait ShaderCompiler<T: OutputTarget> { pub trait ShaderCompiler<T: OutputTarget>: ReflectShader {
type Output; type Output;
type Options; type Options = Option<()>;
type Context = (); type Context = ();
fn compile(&mut self, options: &Self::Options, reflection: &ShaderReflection) -> Result<CompiledShader<Self::Output, Self::Context>, ShaderCompileError>; fn compile(&mut self, options: Self::Options) -> Result<CompiledShader<Self::Output, Self::Context>, ShaderCompileError>;
}
impl ReflectShader for GLSL {
fn reflect(&mut self, pass_number: u32, semantics: &ReflectSemantics) -> Result<ShaderReflection, ShaderReflectError> {
self.0.reflect(pass_number, semantics)
}
}
impl ShaderCompiler<GLSL> for GLSL {
type Output = String;
type Context = Vec<u32>;
fn compile(&mut self, options: Self::Options) -> Result<CompiledShader<Self::Output, Self::Context>, ShaderCompileError> {
self.0.compile(options)
}
}
impl TryFrom<GlslangCompilation> for GLSL {
type Error = ShaderReflectError;
fn try_from(value: GlslangCompilation) -> Result<Self, Self::Error> {
let value = GlslReflect::try_from(value)?;
Ok(Self(value))
}
}
impl ReflectShader for HLSL {
fn reflect(&mut self, pass_number: u32, semantics: &ReflectSemantics) -> Result<ShaderReflection, ShaderReflectError> {
self.0.reflect(pass_number, semantics)
}
}
impl ShaderCompiler<HLSL> for HLSL {
type Output = String;
fn compile(&mut self, options: Self::Options) -> Result<CompiledShader<Self::Output, Self::Context>, ShaderCompileError> {
self.0.compile(options)
}
}
impl TryFrom<GlslangCompilation> for HLSL {
type Error = ShaderReflectError;
fn try_from(value: GlslangCompilation) -> Result<Self, Self::Error> {
let value = HlslReflect::try_from(value)?;
Ok(Self(value))
}
} }

View file

@ -5,14 +5,14 @@ use crate::reflect::semantics::{
TextureSemantics, TextureSizeMeta, TypeInfo, UboReflection, ValidateTypeSemantics, TextureSemantics, TextureSizeMeta, TypeInfo, UboReflection, ValidateTypeSemantics,
VariableMeta, VariableSemantics, MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE, VariableMeta, VariableSemantics, MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE,
}; };
use crate::reflect::{ReflectMeta, ReflectSemantics, ReflectShader, UniformSemantic}; use crate::reflect::{ReflectMeta, ReflectSemantics, ReflectShader, TextureSemanticMap, UniformSemantic, VariableSemanticMap};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use spirv_cross::hlsl::{ShaderModel}; use spirv_cross::hlsl::{ShaderModel};
use spirv_cross::spirv::{Ast, Decoration, Module, Resource, ShaderResources, Type}; use spirv_cross::spirv::{Ast, Decoration, Module, Resource, ShaderResources, Type};
use spirv_cross::{hlsl, ErrorCode, glsl}; use spirv_cross::{hlsl, ErrorCode, glsl};
use std::str::FromStr; use std::str::FromStr;
use spirv_cross::glsl::Version; use spirv_cross::glsl::{Precision, Version};
use crate::back::{CompiledShader, ShaderCompiler}; use crate::back::{CompiledShader, ShaderCompiler};
pub struct CrossReflect<T> pub struct CrossReflect<T>
@ -250,108 +250,6 @@ impl SemanticErrorBlame {
} }
} }
trait TextureSemanticMap<T> {
fn get_texture_semantic(&self, name: &str) -> Option<SemanticMap<TextureSemantics>>;
}
trait VariableSemanticMap<T> {
fn get_variable_semantic(&self, name: &str) -> Option<SemanticMap<VariableSemantics>>;
}
impl VariableSemanticMap<UniformSemantic> for FxHashMap<String, UniformSemantic> {
fn get_variable_semantic(&self, name: &str) -> Option<SemanticMap<VariableSemantics>> {
match self.get(name) {
// existing uniforms in the semantic map have priority
None => match name {
"MVP" => Some(SemanticMap {
semantics: VariableSemantics::MVP,
index: 0,
}),
"OutputSize" => Some(SemanticMap {
semantics: VariableSemantics::Output,
index: 0,
}),
"FinalViewportSize" => Some(SemanticMap {
semantics: VariableSemantics::FinalViewport,
index: 0,
}),
"FrameCount" => Some(SemanticMap {
semantics: VariableSemantics::FrameCount,
index: 0,
}),
"FrameDirection" => Some(SemanticMap {
semantics: VariableSemantics::FrameDirection,
index: 0,
}),
_ => None,
},
Some(UniformSemantic::Variable(variable)) => Some(*variable),
Some(UniformSemantic::Texture(_)) => None,
}
}
}
impl TextureSemanticMap<UniformSemantic> for FxHashMap<String, UniformSemantic> {
fn get_texture_semantic(&self, name: &str) -> Option<SemanticMap<TextureSemantics>> {
match self.get(name) {
None => {
if let Some(semantics) = TextureSemantics::TEXTURE_SEMANTICS
.iter()
.find(|f| name.starts_with(f.size_uniform_name()))
{
if semantics.is_array() {
let index = &name[semantics.size_uniform_name().len()..];
let Ok(index) = u32::from_str(index) else {
return None;
};
return Some(SemanticMap {
semantics: *semantics,
index,
});
} else if name == semantics.size_uniform_name() {
return Some(SemanticMap {
semantics: *semantics,
index: 0,
});
}
}
None
}
Some(UniformSemantic::Variable(_)) => None,
Some(UniformSemantic::Texture(texture)) => Some(*texture),
}
}
}
impl TextureSemanticMap<UniformSemantic> for FxHashMap<String, SemanticMap<TextureSemantics>> {
fn get_texture_semantic(&self, name: &str) -> Option<SemanticMap<TextureSemantics>> {
match self.get(name) {
None => {
if let Some(semantics) = TextureSemantics::TEXTURE_SEMANTICS
.iter()
.find(|f| name.starts_with(f.texture_name()))
{
if semantics.is_array() {
let index = &name[semantics.texture_name().len()..];
let Ok(index) = u32::from_str(index) else {return None};
return Some(SemanticMap {
semantics: *semantics,
index,
});
} else if name == semantics.texture_name() {
return Some(SemanticMap {
semantics: *semantics,
index: 0,
});
}
}
None
}
Some(texture) => Some(*texture),
}
}
}
impl<T> CrossReflect<T> impl<T> CrossReflect<T>
where where
T: spirv_cross::spirv::Target, T: spirv_cross::spirv::Target,
@ -791,13 +689,19 @@ pub type GlslOptions = glsl::CompilerOptions;
impl ShaderCompiler<crate::back::targets::GLSL> for CrossReflect<glsl::Target> { impl ShaderCompiler<crate::back::targets::GLSL> for CrossReflect<glsl::Target> {
type Output = String; type Output = String;
type Options = glsl::CompilerOptions;
type Context = Vec<u32>; type Context = Vec<u32>;
// todo: compile should consume self // todo: compile should consume self
fn compile(&mut self, options: &Self::Options, reflection: &ShaderReflection) -> Result<CompiledShader<Self::Output, Self::Context>, ShaderCompileError> { fn compile(&mut self, _options: Self::Options) -> Result<CompiledShader<Self::Output, Self::Context>, ShaderCompileError> {
self.vertex.set_compiler_options(options)?; let mut options: GlslOptions = Default::default();
self.fragment.set_compiler_options(options)?; // todo: allow adjust ogl version
options.version = Version::V4_60;
options.fragment.default_float_precision = Precision::High;
options.fragment.default_int_precision = Precision::High;
options.enable_420_pack_extension = false;
self.vertex.set_compiler_options(&options)?;
self.fragment.set_compiler_options(&options)?;
let vertex_resources = self.vertex.get_shader_resources()?; let vertex_resources = self.vertex.get_shader_resources()?;
let fragment_resources = self.fragment.get_shader_resources()?; let fragment_resources = self.fragment.get_shader_resources()?;
@ -886,11 +790,13 @@ pub type HlslOptions = hlsl::CompilerOptions;
impl ShaderCompiler<crate::back::targets::HLSL> for CrossReflect<hlsl::Target> { impl ShaderCompiler<crate::back::targets::HLSL> for CrossReflect<hlsl::Target> {
type Output = String; type Output = String;
type Options = hlsl::CompilerOptions;
fn compile(&mut self, options: &Self::Options, reflection: &ShaderReflection) -> Result<CompiledShader<Self::Output>, ShaderCompileError> { fn compile(&mut self, _options: Self::Options) -> Result<CompiledShader<Self::Output>, ShaderCompileError> {
self.vertex.set_compiler_options(options)?; let mut options = hlsl::CompilerOptions::default();
self.fragment.set_compiler_options(options)?; options.shader_model = ShaderModel::V5_0;
self.vertex.set_compiler_options(&options)?;
self.fragment.set_compiler_options(&options)?;
Ok(CompiledShader { Ok(CompiledShader {
vertex: self.vertex.compile()?, vertex: self.vertex.compile()?,

View file

@ -1,3 +1,4 @@
use std::str::FromStr;
use crate::error::{ShaderReflectError}; use crate::error::{ShaderReflectError};
use crate::reflect::semantics::{ use crate::reflect::semantics::{
SemanticMap, TextureImage, TextureSemantics, TextureSizeMeta, VariableMeta, SemanticMap, TextureImage, TextureSemantics, TextureSizeMeta, VariableMeta,
@ -14,6 +15,108 @@ pub trait ReflectShader {
fn reflect(&mut self, pass_number: u32, semantics: &ReflectSemantics) -> Result<ShaderReflection, ShaderReflectError>; fn reflect(&mut self, pass_number: u32, semantics: &ReflectSemantics) -> Result<ShaderReflection, ShaderReflectError>;
} }
pub trait TextureSemanticMap<T> {
fn get_texture_semantic(&self, name: &str) -> Option<SemanticMap<TextureSemantics>>;
}
pub trait VariableSemanticMap<T> {
fn get_variable_semantic(&self, name: &str) -> Option<SemanticMap<VariableSemantics>>;
}
impl VariableSemanticMap<UniformSemantic> for FxHashMap<String, UniformSemantic> {
fn get_variable_semantic(&self, name: &str) -> Option<SemanticMap<VariableSemantics>> {
match self.get(name) {
// existing uniforms in the semantic map have priority
None => match name {
"MVP" => Some(SemanticMap {
semantics: VariableSemantics::MVP,
index: 0,
}),
"OutputSize" => Some(SemanticMap {
semantics: VariableSemantics::Output,
index: 0,
}),
"FinalViewportSize" => Some(SemanticMap {
semantics: VariableSemantics::FinalViewport,
index: 0,
}),
"FrameCount" => Some(SemanticMap {
semantics: VariableSemantics::FrameCount,
index: 0,
}),
"FrameDirection" => Some(SemanticMap {
semantics: VariableSemantics::FrameDirection,
index: 0,
}),
_ => None,
},
Some(UniformSemantic::Variable(variable)) => Some(*variable),
Some(UniformSemantic::Texture(_)) => None,
}
}
}
impl TextureSemanticMap<UniformSemantic> for FxHashMap<String, UniformSemantic> {
fn get_texture_semantic(&self, name: &str) -> Option<SemanticMap<TextureSemantics>> {
match self.get(name) {
None => {
if let Some(semantics) = TextureSemantics::TEXTURE_SEMANTICS
.iter()
.find(|f| name.starts_with(f.size_uniform_name()))
{
if semantics.is_array() {
let index = &name[semantics.size_uniform_name().len()..];
let Ok(index) = u32::from_str(index) else {
return None;
};
return Some(SemanticMap {
semantics: *semantics,
index,
});
} else if name == semantics.size_uniform_name() {
return Some(SemanticMap {
semantics: *semantics,
index: 0,
});
}
}
None
}
Some(UniformSemantic::Variable(_)) => None,
Some(UniformSemantic::Texture(texture)) => Some(*texture),
}
}
}
impl TextureSemanticMap<UniformSemantic> for FxHashMap<String, SemanticMap<TextureSemantics>> {
fn get_texture_semantic(&self, name: &str) -> Option<SemanticMap<TextureSemantics>> {
match self.get(name) {
None => {
if let Some(semantics) = TextureSemantics::TEXTURE_SEMANTICS
.iter()
.find(|f| name.starts_with(f.texture_name()))
{
if semantics.is_array() {
let index = &name[semantics.texture_name().len()..];
let Ok(index) = u32::from_str(index) else {return None};
return Some(SemanticMap {
semantics: *semantics,
index,
});
} else if name == semantics.texture_name() {
return Some(SemanticMap {
semantics: *semantics,
index: 0,
});
}
}
None
}
Some(texture) => Some(*texture),
}
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum UniformSemantic { pub enum UniformSemantic {
Variable(SemanticMap<VariableSemantics>), Variable(SemanticMap<VariableSemantics>),

View file

@ -10,7 +10,6 @@ edition = "2021"
"librashader-presets" = { path = "../librashader-presets" } "librashader-presets" = { path = "../librashader-presets" }
"librashader-preprocess" = { path = "../librashader-preprocess" } "librashader-preprocess" = { path = "../librashader-preprocess" }
"librashader-reflect" = { path = "../librashader-reflect" } "librashader-reflect" = { path = "../librashader-reflect" }
spirv_cross = { version = "0.23.1", features = [ "hlsl" ] }
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
[dependencies.windows] [dependencies.windows]

View file

@ -2,10 +2,10 @@ use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::path::Path; use std::path::Path;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use spirv_cross::hlsl::ShaderModel;
use librashader::ShaderSource; use librashader::ShaderSource;
use librashader_presets::ShaderPassConfig; use librashader_presets::ShaderPassConfig;
use librashader_reflect::back::ShaderCompiler; use librashader_reflect::back::ShaderCompiler;
use librashader_reflect::back::targets::HLSL;
use librashader_reflect::front::shaderc::GlslangCompilation; use librashader_reflect::front::shaderc::GlslangCompilation;
use librashader_reflect::reflect::cross::{CrossReflect, HlslOptions, HlslReflect}; use librashader_reflect::reflect::cross::{CrossReflect, HlslOptions, HlslReflect};
use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic}; use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic};
@ -49,13 +49,13 @@ pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSema
pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{ pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
let preset = librashader_presets::ShaderPreset::try_parse(path)?; let preset = librashader_presets::ShaderPreset::try_parse(path)?;
let mut passes: Vec<(&ShaderPassConfig, ShaderSource, HlslReflect)> = preset.shaders.iter() let mut passes: Vec<(&ShaderPassConfig, ShaderSource, HLSL)> = preset.shaders.iter()
.map(|shader| { .map(|shader| {
let source = librashader_preprocess::load_shader_source(&shader.name) let source = librashader_preprocess::load_shader_source(&shader.name)
.unwrap(); .unwrap();
let spirv = librashader_reflect::front::shaderc::compile_spirv(&source) let spirv = librashader_reflect::front::shaderc::compile_spirv(&source)
.unwrap(); .unwrap();
let mut reflect = librashader_reflect::reflect::cross::HlslReflect::try_from(spirv).unwrap(); let mut reflect = librashader_reflect::back::targets::HLSL::try_from(spirv).unwrap();
(shader, source, reflect) (shader, source, reflect)
}).collect(); }).collect();
@ -94,10 +94,8 @@ pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
for (index, (_, _, reflect)) in passes.iter_mut().enumerate() { for (index, (_, _, reflect)) in passes.iter_mut().enumerate() {
let reflection = reflect.reflect(index as u32, &semantics) let reflection = reflect.reflect(index as u32, &semantics)
.unwrap(); .unwrap();
let mut options: HlslOptions = Default::default();
options.shader_model = ShaderModel::V5_0;
let hlsl = reflect.compile(&options, &reflection) let hlsl = reflect.compile(None)
.unwrap(); .unwrap();
eprintln!("{:#}", hlsl.vertex); eprintln!("{:#}", hlsl.vertex);

View file

@ -10,7 +10,6 @@ edition = "2021"
"librashader-presets" = { path = "../librashader-presets" } "librashader-presets" = { path = "../librashader-presets" }
"librashader-preprocess" = { path = "../librashader-preprocess" } "librashader-preprocess" = { path = "../librashader-preprocess" }
"librashader-reflect" = { path = "../librashader-reflect" } "librashader-reflect" = { path = "../librashader-reflect" }
spirv_cross = { version = "0.23.1", features = [ "hlsl" ] }
rustc-hash = "1.1.0" rustc-hash = "1.1.0"
[dependencies.windows] [dependencies.windows]

View file

@ -2,16 +2,16 @@ use std::collections::HashMap;
use std::error::Error; use std::error::Error;
use std::path::Path; use std::path::Path;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use spirv_cross::glsl::{Precision, Version};
use spirv_cross::hlsl::ShaderModel;
use librashader::ShaderSource; use librashader::ShaderSource;
use librashader_presets::ShaderPassConfig; use librashader_presets::ShaderPassConfig;
use librashader_reflect::back::ShaderCompiler; use librashader_reflect::back::ShaderCompiler;
use librashader_reflect::back::targets::GLSL;
use librashader_reflect::front::shaderc::GlslangCompilation; use librashader_reflect::front::shaderc::GlslangCompilation;
use librashader_reflect::reflect::cross::{CrossReflect, GlslOptions, GlslReflect, HlslOptions, HlslReflect}; use librashader_reflect::reflect::cross::{CrossReflect, GlslOptions, GlslReflect, HlslOptions, HlslReflect};
use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic}; use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic};
use librashader_reflect::reflect::semantics::{SemanticMap, TextureSemantics, VariableSemantics}; use librashader_reflect::reflect::semantics::{SemanticMap, TextureSemantics, VariableSemantics};
use librashader_reflect::reflect::{TextureSemanticMap, VariableSemanticMap};
pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSemantic>, texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>, pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSemantic>, texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
config: &ShaderPassConfig) { config: &ShaderPassConfig) {
@ -50,13 +50,13 @@ pub fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSema
pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{ pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
let preset = librashader_presets::ShaderPreset::try_parse(path)?; let preset = librashader_presets::ShaderPreset::try_parse(path)?;
let mut passes: Vec<(&ShaderPassConfig, ShaderSource, GlslReflect)> = preset.shaders.iter() let mut passes: Vec<(&ShaderPassConfig, ShaderSource, GLSL)> = preset.shaders.iter()
.map(|shader| { .map(|shader| {
let source = librashader_preprocess::load_shader_source(&shader.name) let source = librashader_preprocess::load_shader_source(&shader.name)
.unwrap(); .unwrap();
let spirv = librashader_reflect::front::shaderc::compile_spirv(&source) let spirv = librashader_reflect::front::shaderc::compile_spirv(&source)
.unwrap(); .unwrap();
let mut reflect = librashader_reflect::reflect::cross::GlslReflect::try_from(spirv).unwrap(); let mut reflect = librashader_reflect::back::targets::GLSL::try_from(spirv).unwrap();
(shader, source, reflect) (shader, source, reflect)
}).collect(); }).collect();
@ -92,33 +92,35 @@ pub fn load(path: impl AsRef<Path>) -> Result<(), Box<dyn Error>>{
let mut reflections = Vec::new(); let mut reflections = Vec::new();
let mut compiled = Vec::new(); let mut compiled = Vec::new();
for (index, (_, _, reflect)) in passes.iter_mut().enumerate() { for (index, (config, source, reflect)) in passes.iter_mut().enumerate() {
let reflection = reflect.reflect(index as u32, &semantics) let reflection = reflect.reflect(index as u32, &semantics)
.unwrap(); .unwrap();
let mut options: GlslOptions = Default::default();
// todo: adjust ogl version
options.version = Version::V4_60;
options.fragment.default_float_precision = Precision::High;
options.fragment.default_int_precision = Precision::High;
options.enable_420_pack_extension = false;
let glsl = reflect.compile(&options, &reflection) let glsl = reflect.compile(None)
.unwrap(); .unwrap();
eprintln!("{:#}", glsl.vertex); eprintln!("{:#}", glsl.vertex);
eprintln!("{:#}", glsl.fragment); eprintln!("{:#}", glsl.fragment);
// shader_gl3: 1375
reflection.meta.texture_meta.get(&SemanticMap {
semantics: TextureSemantics::PassOutput,
index: 0
}).unwrap().binding;
compiled.push(glsl); compiled.push(glsl);
reflections.push(reflection); reflections.push(reflection);
} }
// todo: build gl semantics
// shader_gl3:188
eprintln!("{:#?}", reflections); eprintln!("{:#?}", reflections);
eprintln!("{:#?}", compiled); eprintln!("{:#?}", compiled);
// //todo: add the semantics for other shit (slang_process:68)
// eprintln!("{:?}", preset); // eprintln!("{:?}", preset);
// eprintln!("{:?}", reflect.reflect(&ReflectOptions { // eprintln!("{:?}", reflect.reflect(&ReflectOptions {
// pass_number: i as u32, // pass_number: i as u32,