From 9ab67300071606cd0a4c44c1e7994fdcf969a873 Mon Sep 17 00:00:00 2001 From: Mehmet Oguz Derin Date: Sun, 2 Mar 2025 11:26:17 +0900 Subject: [PATCH 1/5] Update subproject commits for glslang, shaderc, spirv-headers, and spirv-tools --- shaderc-sys/build/glslang | 2 +- shaderc-sys/build/shaderc | 2 +- shaderc-sys/build/spirv-headers | 2 +- shaderc-sys/build/spirv-tools | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shaderc-sys/build/glslang b/shaderc-sys/build/glslang index 1fb2f1d..8b822ee 160000 --- a/shaderc-sys/build/glslang +++ b/shaderc-sys/build/glslang @@ -1 +1 @@ -Subproject commit 1fb2f1d7896627d62a289439a2c3e750e551a7ab +Subproject commit 8b822ee8ac2c3e52926820f46ad858532a895951 diff --git a/shaderc-sys/build/shaderc b/shaderc-sys/build/shaderc index 69aead4..0968768 160000 --- a/shaderc-sys/build/shaderc +++ b/shaderc-sys/build/shaderc @@ -1 +1 @@ -Subproject commit 69aead488f9761c3bf478deda5999549ffec2c28 +Subproject commit 0968768c61d4eb7dd861114412e904bb3d59b7b6 diff --git a/shaderc-sys/build/spirv-headers b/shaderc-sys/build/spirv-headers index d13b522..54a521d 160000 --- a/shaderc-sys/build/spirv-headers +++ b/shaderc-sys/build/spirv-headers @@ -1 +1 @@ -Subproject commit d13b52222c39a7e9a401b44646f0ca3a640fbd47 +Subproject commit 54a521dd130ae1b2f38fef79b09515702d135bdd diff --git a/shaderc-sys/build/spirv-tools b/shaderc-sys/build/spirv-tools index 63de608..f289d04 160000 --- a/shaderc-sys/build/spirv-tools +++ b/shaderc-sys/build/spirv-tools @@ -1 +1 @@ -Subproject commit 63de608daeb7e91fbea6d7477a50debe7cac57ce +Subproject commit f289d047f49fb60488301ec62bafab85573668cc From c7eb3bd27422bbfa0f296f0a20cad1fb03643d62 Mon Sep 17 00:00:00 2001 From: Mehmet Oguz Derin Date: Sun, 2 Mar 2025 12:17:21 +0900 Subject: [PATCH 2/5] Bump version to 0.9.0 for shaderc and shaderc-sys --- shaderc-rs/Cargo.toml | 4 +- shaderc-rs/src/lib.rs | 146 +++++++++++++++++++++++++---------------- shaderc-sys/Cargo.toml | 2 +- 3 files changed, 93 insertions(+), 59 deletions(-) diff --git a/shaderc-rs/Cargo.toml b/shaderc-rs/Cargo.toml index 77977b3..4b97026 100644 --- a/shaderc-rs/Cargo.toml +++ b/shaderc-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shaderc" -version = "0.8.3" +version = "0.9.0" authors = ["Lei Zhang "] description = "Rust bindings for shaderc" documentation = "https://docs.rs/shaderc" @@ -14,7 +14,7 @@ path = "src/lib.rs" [dependencies] libc = "0.2" -shaderc-sys = { version = "0.8.3", path = "../shaderc-sys" } +shaderc-sys = { version = "0.9.0", path = "../shaderc-sys" } [dev-dependencies] assert_matches = "1.5" diff --git a/shaderc-rs/src/lib.rs b/shaderc-rs/src/lib.rs index 4935962..6421978 100644 --- a/shaderc-rs/src/lib.rs +++ b/shaderc-rs/src/lib.rs @@ -80,62 +80,87 @@ use std::{error, fmt, ptr, result, slice, str}; /// Error. /// -/// Each enumerants has an affixed string describing detailed reasons for -/// the error. The string can be empty in cases. +/// Each enumerant has an affixed string describing detailed reasons for +/// the error. The string can be empty in certain cases. #[derive(Debug, PartialEq)] pub enum Error { /// Compilation error. /// - /// Contains the number of errors and detailed error string. + /// Contains the number of errors and a detailed error string. CompilationError(u32, String), InternalError(String), InvalidStage(String), InvalidAssembly(String), NullResultObject(String), + + /// Returned when an internal initialization fails, for instance creating + /// a `Compiler` or `CompileOptions` fails because the underlying shaderc + /// function returned null. + InitializationError(String), + + /// Returned when string parsing fails (e.g., version/profile parsing). + ParseError(String), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::CompilationError(c, ref r) => { - if c == 1 { + Error::CompilationError(count, ref reason) => { + if count == 1 { write!(f, "compilation error")?; } else { - write!(f, "{c} compilation errors")?; + write!(f, "{} compilation errors", count)?; } - - if !r.is_empty() { - write!(f, ":{}{}", if r.contains('\n') { "\n" } else { " " }, r)?; + if !reason.is_empty() { + write!( + f, + ":{}{}", + if reason.contains('\n') { "\n" } else { " " }, + reason + )?; } - Ok(()) } Error::InternalError(ref r) => { if r.is_empty() { write!(f, "internal error") } else { - write!(f, "internal error: {r}") + write!(f, "internal error: {}", r) } } Error::InvalidStage(ref r) => { if r.is_empty() { write!(f, "invalid stage") } else { - write!(f, "invalid stage: {r}") + write!(f, "invalid stage: {}", r) } } Error::InvalidAssembly(ref r) => { if r.is_empty() { write!(f, "invalid assembly") } else { - write!(f, "invalid assembly: {r}") + write!(f, "invalid assembly: {}", r) } } Error::NullResultObject(ref r) => { if r.is_empty() { write!(f, "null result object") } else { - write!(f, "null result object: {r}") + write!(f, "null result object: {}", r) + } + } + Error::InitializationError(ref r) => { + if r.is_empty() { + write!(f, "initialization error") + } else { + write!(f, "initialization error: {}", r) + } + } + Error::ParseError(ref r) => { + if r.is_empty() { + write!(f, "parse error") + } else { + write!(f, "parse error: {}", r) } } } @@ -150,6 +175,8 @@ impl error::Error for Error { Error::InvalidStage(_) => "invalid stage", Error::InvalidAssembly(_) => "invalid assembly", Error::NullResultObject(_) => "null result object", + Error::InitializationError(_) => "initialization error", + Error::ParseError(_) => "parse error", } } } @@ -455,7 +482,7 @@ where /// a UTF-8 string fn safe_str_from_utf8(bytes: &[u8]) -> String { match str::from_utf8(bytes) { - Ok(str) => str.to_string(), + Ok(s) => s.to_string(), Err(err) => { if err.valid_up_to() > 0 { format!( @@ -463,23 +490,25 @@ fn safe_str_from_utf8(bytes: &[u8]) -> String { safe_str_from_utf8(&bytes[..err.valid_up_to()]) ) } else { - format!("invalid UTF-8 string: {err}") + format!("invalid UTF-8 string: {}", err) } } } } impl Compiler { - /// Returns an compiler object that can be used to compile SPIR-V modules. + /// Returns a `Compiler` object that can be used to compile SPIR-V modules. /// - /// A return of `None` indicates that there was an error initializing - /// the underlying compiler. - pub fn new() -> Option { + /// A return of `Err` indicates that there was an error initializing + /// the underlying compiler (i.e., `shaderc_compiler_initialize()` returned null). + pub fn new() -> Result { let p = unsafe { scs::shaderc_compiler_initialize() }; if p.is_null() { - None + Err(Error::InitializationError( + "Failed to create a shaderc compiler.".to_string(), + )) } else { - Some(Compiler { raw: p }) + Ok(Compiler { raw: p }) } } @@ -708,14 +737,15 @@ impl<'a> CompileOptions<'a> { /// * Target environment: Vulkan /// * Source language: GLSL /// - /// A return of `None` indicates that there was an error initializing - /// the underlying options object. - pub fn new() -> Option> { + /// Returns `Err(Error::InitializationError)` if creation failed. + pub fn new() -> Result> { let p = unsafe { scs::shaderc_compile_options_initialize() }; if p.is_null() { - None + Err(Error::InitializationError( + "Failed to create CompileOptions.".to_string(), + )) } else { - Some(CompileOptions { + Ok(CompileOptions { raw: p, include_callback_fn: None, }) @@ -724,30 +754,34 @@ impl<'a> CompileOptions<'a> { /// Returns a copy of the given compilation options object. /// - /// A return of `None` indicates that there was an error copying - /// the underlying options object. + /// Returns `Err(Error::InitializationError)` if the clone operation failed (underlying call + /// returned null). #[allow(clippy::should_implement_trait)] - pub fn clone(&self) -> Option { + pub fn clone(&self) -> Result> { let p = unsafe { scs::shaderc_compile_options_clone(self.raw) }; if p.is_null() { - None + Err(Error::InitializationError( + "Failed to clone CompileOptions.".to_string(), + )) } else { - Some(CompileOptions { + Ok(CompileOptions { raw: p, include_callback_fn: None, }) } } - /// Sets the target enviroment to `env`, affecting which warnings or errors + /// Sets the target environment to `env`, affecting which warnings or errors /// will be issued. /// /// The default is Vulkan if not set. /// /// `version` will be used for distinguishing between different versions /// of the target environment. - /// Note that EnvVersion must be cast to u32 when calling set_target_env. - /// For example: `options.set_target_env(shaderc::TargetEnv::Vulkan, shaderc::EnvVersion::Vulkan1_1 as u32);` + /// For example: + /// ```ignore + /// options.set_target_env(shaderc::TargetEnv::Vulkan, shaderc::EnvVersion::Vulkan1_1 as u32); + /// ``` pub fn set_target_env(&mut self, env: TargetEnv, version: u32) { unsafe { scs::shaderc_compile_options_set_target_env(self.raw, env as i32, version) } } @@ -1005,9 +1039,9 @@ impl<'a> CompileOptions<'a> { /// Sets a descriptor set and binding for an HLSL register in all shader stages. pub fn set_hlsl_register_set_and_binding(&mut self, register: &str, set: &str, binding: &str) { - let c_register = CString::new(register).expect("cannot convert string to c string"); - let c_set = CString::new(set).expect("cannot convert string to c string"); - let c_binding = CString::new(binding).expect("cannot convert string to c string"); + let c_register = CString::new(register).expect("cannot convert register to c string"); + let c_set = CString::new(set).expect("cannot convert set to c string"); + let c_binding = CString::new(binding).expect("cannot convert binding to c string"); unsafe { scs::shaderc_compile_options_set_hlsl_register_set_and_binding( self.raw, @@ -1055,7 +1089,7 @@ impl<'a> CompileOptions<'a> { } } - /// Sets whether the compiler should invert position.Y output in vertex shader. + /// Sets whether the compiler should invert position.Y output in a vertex shader. pub fn set_invert_y(&mut self, enable: bool) { unsafe { scs::shaderc_compile_options_set_invert_y(self.raw, enable); @@ -1080,9 +1114,9 @@ impl<'a> CompileOptions<'a> { /// same name has previously been added, the value is replaced with the /// new value. pub fn add_macro_definition(&mut self, name: &str, value: Option<&str>) { - let c_name = CString::new(name).expect("cannot convert name to c string"); + let c_name = CString::new(name).expect("cannot convert macro name to c string"); if let Some(value) = value { - let c_value = CString::new(value).expect("cannot convert value to c string"); + let c_value = CString::new(value).expect("cannot convert macro value to c string"); unsafe { scs::shaderc_compile_options_add_macro_definition( self.raw, @@ -1107,7 +1141,7 @@ impl<'a> CompileOptions<'a> { /// Sets the optimization level to `level`. /// - /// If mulitple invocations for this method, only the last one takes effect. + /// If multiple invocations for this method, only the last one takes effect. pub fn set_optimization_level(&mut self, level: OptimizationLevel) { unsafe { scs::shaderc_compile_options_set_optimization_level(self.raw, level as i32) } } @@ -1168,8 +1202,7 @@ impl CompilationArtifact { /// /// # Panics /// - /// This method will panic if the compilation does not generate a - /// binary output. + /// Panics if the compilation does not generate a binary output. pub fn as_binary(&self) -> &[u32] { if !self.is_binary { panic!("not binary result") @@ -1189,8 +1222,7 @@ impl CompilationArtifact { /// /// # Panics /// - /// This method will panic if the compilation does not generate a - /// binary output. + /// Panics if the compilation does not generate a binary output. pub fn as_binary_u8(&self) -> &[u8] { if !self.is_binary { panic!("not binary result") @@ -1208,8 +1240,7 @@ impl CompilationArtifact { /// /// # Panics /// - /// This method will panic if the compilation does not generate a - /// text output. + /// Panics if the compilation does not generate a text output. pub fn as_text(&self) -> String { if self.is_binary { panic!("not text result") @@ -1225,7 +1256,7 @@ impl CompilationArtifact { /// Returns the number of warnings generated during the compilation. pub fn get_num_warnings(&self) -> u32 { - (unsafe { scs::shaderc_result_get_num_warnings(self.raw) }) as u32 + unsafe { scs::shaderc_result_get_num_warnings(self.raw) as u32 } } /// Returns the detailed warnings as a string. @@ -1256,11 +1287,11 @@ pub fn get_spirv_version() -> (u32, u32) { (version as u32, revision as u32) } -/// Parses the version and profile from the given `string`. +/// Parses the version and profile from the given `string`, returning a `Result`. /// -/// The string should contain both version and profile, like: `450core`. -/// Returns `None` if the string can not be parsed. -pub fn parse_version_profile(string: &str) -> Option<(u32, GlslProfile)> { +/// The string should contain both version and profile, like `450core`. +/// Returns an error if the string cannot be parsed. +pub fn parse_version_profile(string: &str) -> Result<(u32, GlslProfile)> { let mut version: i32 = 0; let mut profile: i32 = 0; let c_string = CString::new(string).expect("cannot convert string to c string"); @@ -1268,16 +1299,19 @@ pub fn parse_version_profile(string: &str) -> Option<(u32, GlslProfile)> { scs::shaderc_parse_version_profile(c_string.as_ptr(), &mut version, &mut profile) }; if !result { - None + Err(Error::ParseError(format!( + "Failed to parse version/profile from '{}'", + string + ))) } else { let p = match profile { 0 => GlslProfile::None, 1 => GlslProfile::Core, 2 => GlslProfile::Compatibility, 3 => GlslProfile::Es, - _ => panic!("internal error: unhandled profile"), + _ => panic!("internal error: unhandled profile value {}", profile), }; - Some((version as u32, p)) + Ok((version as u32, p)) } } diff --git a/shaderc-sys/Cargo.toml b/shaderc-sys/Cargo.toml index cfdd1d4..d10e769 100644 --- a/shaderc-sys/Cargo.toml +++ b/shaderc-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "shaderc-sys" -version = "0.8.3" +version = "0.9.0" authors = ["Lei Zhang ", "Mr. Knapp "] build = "build/build.rs" description = "Shaderc system library FFI, building, and linking" From 2747f888fd9adb1558ab50e488ab534f17559d24 Mon Sep 17 00:00:00 2001 From: Mehmet Oguz Derin Date: Sun, 2 Mar 2025 21:27:38 +0900 Subject: [PATCH 3/5] Refactor error messages to use formatted strings for clippy --- shaderc-rs/src/lib.rs | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/shaderc-rs/src/lib.rs b/shaderc-rs/src/lib.rs index 6421978..339ed50 100644 --- a/shaderc-rs/src/lib.rs +++ b/shaderc-rs/src/lib.rs @@ -109,7 +109,7 @@ impl fmt::Display for Error { if count == 1 { write!(f, "compilation error")?; } else { - write!(f, "{} compilation errors", count)?; + write!(f, "{count} compilation errors")?; } if !reason.is_empty() { write!( @@ -125,42 +125,42 @@ impl fmt::Display for Error { if r.is_empty() { write!(f, "internal error") } else { - write!(f, "internal error: {}", r) + write!(f, "internal error: {r}") } } Error::InvalidStage(ref r) => { if r.is_empty() { write!(f, "invalid stage") } else { - write!(f, "invalid stage: {}", r) + write!(f, "invalid stage: {r}") } } Error::InvalidAssembly(ref r) => { if r.is_empty() { write!(f, "invalid assembly") } else { - write!(f, "invalid assembly: {}", r) + write!(f, "invalid assembly: {r}") } } Error::NullResultObject(ref r) => { if r.is_empty() { write!(f, "null result object") } else { - write!(f, "null result object: {}", r) + write!(f, "null result object: {r}") } } Error::InitializationError(ref r) => { if r.is_empty() { write!(f, "initialization error") } else { - write!(f, "initialization error: {}", r) + write!(f, "initialization error: {r}") } } Error::ParseError(ref r) => { if r.is_empty() { write!(f, "parse error") } else { - write!(f, "parse error: {}", r) + write!(f, "parse error: {r}") } } } @@ -490,7 +490,7 @@ fn safe_str_from_utf8(bytes: &[u8]) -> String { safe_str_from_utf8(&bytes[..err.valid_up_to()]) ) } else { - format!("invalid UTF-8 string: {}", err) + format!("invalid UTF-8 string: {err}") } } } @@ -1300,8 +1300,7 @@ pub fn parse_version_profile(string: &str) -> Result<(u32, GlslProfile)> { }; if !result { Err(Error::ParseError(format!( - "Failed to parse version/profile from '{}'", - string + "Failed to parse version/profile from '{string}'" ))) } else { let p = match profile { @@ -1426,7 +1425,7 @@ void main() { my_ssbo.x = 1.0; }"; let result = c .preprocess(VOID_E, "shader.glsl", "main", Some(&options)) .unwrap(); - assert_eq!("#version 310 es\n void main(){ }\n", result.as_text()); + assert_eq!("#version 310 es\n void main() { }\n", result.as_text()); } #[test] @@ -2035,13 +2034,23 @@ void main() { my_ssbo.x = 1.0; }"; #[test] fn test_parse_version_profile() { - assert_eq!(Some((310, GlslProfile::Es)), parse_version_profile("310es")); + assert_eq!(Ok((310, GlslProfile::Es)), parse_version_profile("310es")); assert_eq!( - Some((450, GlslProfile::Compatibility)), + Ok((450, GlslProfile::Compatibility)), parse_version_profile("450compatibility") ); - assert_eq!(Some((140, GlslProfile::None)), parse_version_profile("140")); - assert_eq!(None, parse_version_profile("something")); - assert_eq!(None, parse_version_profile("")); + assert_eq!(Ok((140, GlslProfile::None)), parse_version_profile("140")); + assert_eq!( + Err(Error::ParseError( + "Failed to parse version/profile from 'something'".to_string() + )), + parse_version_profile("something") + ); + assert_eq!( + Err(Error::ParseError( + "Failed to parse version/profile from ''".to_string() + )), + parse_version_profile("") + ); } } From 33ef2b37eb92af0a1f4ffe99a373ae2d094128cb Mon Sep 17 00:00:00 2001 From: Mehmet Oguz Derin Date: Mon, 10 Mar 2025 09:22:06 +0900 Subject: [PATCH 4/5] Address feedback --- shaderc-rs/src/lib.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/shaderc-rs/src/lib.rs b/shaderc-rs/src/lib.rs index 482753b..eabfc04 100644 --- a/shaderc-rs/src/lib.rs +++ b/shaderc-rs/src/lib.rs @@ -505,7 +505,7 @@ impl Compiler { let p = unsafe { scs::shaderc_compiler_initialize() }; if p.is_null() { Err(Error::InitializationError( - "Failed to create a shaderc compiler.".to_string(), + "failed to create a shaderc compiler.".to_string(), )) } else { Ok(Compiler { raw: p }) @@ -742,7 +742,7 @@ impl<'a> CompileOptions<'a> { let p = unsafe { scs::shaderc_compile_options_initialize() }; if p.is_null() { Err(Error::InitializationError( - "Failed to create CompileOptions.".to_string(), + "failed to create CompileOptions.".to_string(), )) } else { Ok(CompileOptions { @@ -761,7 +761,7 @@ impl<'a> CompileOptions<'a> { let p = unsafe { scs::shaderc_compile_options_clone(self.raw) }; if p.is_null() { Err(Error::InitializationError( - "Failed to clone CompileOptions.".to_string(), + "failed to clone CompileOptions.".to_string(), )) } else { Ok(CompileOptions { @@ -1300,7 +1300,7 @@ pub fn parse_version_profile(string: &str) -> Result<(u32, GlslProfile)> { }; if !result { Err(Error::ParseError(format!( - "Failed to parse version/profile from '{string}'" + "failed to parse version/profile from '{string}'" ))) } else { let p = match profile { @@ -1635,11 +1635,11 @@ void main() { my_ssbo.x = 1.0; }"; } #[test] - #[should_panic(expected = "Panic in include resolver!")] + #[should_panic(expected = "panic in include resolver!")] fn test_include_directive_panic() { let c = Compiler::new().unwrap(); let mut options = CompileOptions::new().unwrap(); - options.set_include_callback(|_, _, _, _| panic!("Panic in include resolver!")); + options.set_include_callback(|_, _, _, _| panic!("panic in include resolver!")); drop(c.compile_into_spirv_assembly( r#" #version 400 @@ -1657,7 +1657,7 @@ void main() { my_ssbo.x = 1.0; }"; let c = Compiler::new().unwrap(); let mut options = CompileOptions::new().unwrap(); options - .set_include_callback(|name, _, _, _| Err(format!("Couldn't find header \"{name}\""))); + .set_include_callback(|name, _, _, _| Err(format!("couldn't find header \"{name}\""))); let result = c.compile_into_spirv_assembly( r#" #version 400 @@ -1671,7 +1671,7 @@ void main() { my_ssbo.x = 1.0; }"; assert!(result.is_err()); assert_matches!(result.err(), Some(Error::CompilationError(1, ref s)) - if s.contains("Couldn't find header \"foo.glsl\"")); + if s.contains("couldn't find header \"foo.glsl\"")); } #[test] @@ -1691,7 +1691,7 @@ void main() { my_ssbo.x = 1.0; }"; .to_string(), }) } else { - Err(format!("Couldn't find header \"{name}\"")) + Err(format!("couldn't find header \"{name}\"")) } }); let result = c.compile_into_spirv_assembly( @@ -2042,13 +2042,13 @@ void main() { my_ssbo.x = 1.0; }"; assert_eq!(Ok((140, GlslProfile::None)), parse_version_profile("140")); assert_eq!( Err(Error::ParseError( - "Failed to parse version/profile from 'something'".to_string() + "failed to parse version/profile from 'something'".to_string() )), parse_version_profile("something") ); assert_eq!( Err(Error::ParseError( - "Failed to parse version/profile from ''".to_string() + "failed to parse version/profile from ''".to_string() )), parse_version_profile("") ); From d0e615e0dbbb916d210fd73cc61f3bfd882616bc Mon Sep 17 00:00:00 2001 From: Mehmet Oguz Derin Date: Mon, 10 Mar 2025 09:26:11 +0900 Subject: [PATCH 5/5] Address more feedback --- shaderc-rs/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shaderc-rs/src/lib.rs b/shaderc-rs/src/lib.rs index eabfc04..3d69cf6 100644 --- a/shaderc-rs/src/lib.rs +++ b/shaderc-rs/src/lib.rs @@ -505,7 +505,7 @@ impl Compiler { let p = unsafe { scs::shaderc_compiler_initialize() }; if p.is_null() { Err(Error::InitializationError( - "failed to create a shaderc compiler.".to_string(), + "failed to create a shaderc compiler".to_string(), )) } else { Ok(Compiler { raw: p }) @@ -742,7 +742,7 @@ impl<'a> CompileOptions<'a> { let p = unsafe { scs::shaderc_compile_options_initialize() }; if p.is_null() { Err(Error::InitializationError( - "failed to create CompileOptions.".to_string(), + "failed to create CompileOptions".to_string(), )) } else { Ok(CompileOptions { @@ -761,7 +761,7 @@ impl<'a> CompileOptions<'a> { let p = unsafe { scs::shaderc_compile_options_clone(self.raw) }; if p.is_null() { Err(Error::InitializationError( - "failed to clone CompileOptions.".to_string(), + "failed to clone CompileOptions".to_string(), )) } else { Ok(CompileOptions {