Skip to content

Commit 5f1e202

Browse files
authored
Avoid pointer redirection for Optional slices in Go (1Password#198)
* Avoid pointer redirection for Optional slices * Fix Go tests * Add no pointer redirection for slices as a go configuration option * Run cargo fmt * Avoid using unnecessary local variables * Revert cargo.lock changes * Add tests and more documentation
1 parent a509825 commit 5f1e202

File tree

4 files changed

+55
-3
lines changed

4 files changed

+55
-3
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cli/src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub struct TypeScriptParams {
5050
pub struct GoParams {
5151
pub package: String,
5252
pub uppercase_acronyms: Vec<String>,
53+
pub no_pointer_slice: bool,
5354
pub type_mappings: HashMap<String, String>,
5455
}
5556

cli/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ fn language(
186186
package: config.go.package,
187187
type_mappings: config.go.type_mappings,
188188
uppercase_acronyms: config.go.uppercase_acronyms,
189+
no_pointer_slice: config.go.no_pointer_slice,
189190
..Default::default()
190191
}),
191192
#[cfg(not(feature = "go"))]

core/src/language/go.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,24 @@ pub struct Go {
2525
/// Whether or not to exclude the version header that normally appears at the top of generated code.
2626
/// If you aren't generating a snapshot test, this setting can just be left as a default (false)
2727
pub no_version_header: bool,
28+
/// Whether or not slices should be translated with a pointer redirection.
29+
///
30+
/// It is rather unusual in Go to have pointers to slices. This is because, in Go, slices are already reference types.
31+
/// However, an edge case can occur:
32+
///
33+
/// type A struct {
34+
/// Slice []string `json:",omitempty"`
35+
/// }
36+
///
37+
/// type B struct {
38+
/// Slice *[]string `json:",omitempty"`
39+
/// }
40+
/// For type A, both Slice: nil and Slice: []string{} have the same JSON serialisation (Slice is omitted).
41+
/// For type B Slice: nil and Slice: []string{} both have a different JSON serialisation.
42+
/// In the first case, Slice is omitted. In the second case the field has the value [].
43+
///
44+
/// This, however, is rarely applicable in practice, and having this feature does not justify exposing an unintuitive user interface.
45+
pub no_pointer_slice: bool,
2846
}
2947

3048
impl Language for Go {
@@ -102,7 +120,15 @@ impl Language for Go {
102120
format!("[]{}", self.format_type(rtype, generic_types)?)
103121
}
104122
SpecialRustType::Option(rtype) => {
105-
format!("*{}", self.format_type(rtype, generic_types)?)
123+
format!(
124+
"{}{}",
125+
if rtype.is_vec() && self.no_pointer_slice {
126+
""
127+
} else {
128+
"*"
129+
},
130+
self.format_type(rtype, generic_types)?
131+
)
106132
}
107133
SpecialRustType::HashMap(rtype1, rtype2) => format!(
108134
"map[{}]{}",
@@ -505,3 +531,27 @@ fn convert_acronyms_to_uppercase(uppercase_acronyms: Vec<String>, name: &str) ->
505531
}
506532
res
507533
}
534+
535+
mod test {
536+
#[test]
537+
fn no_pointer_slice() {
538+
let mut go = super::Go {
539+
..Default::default()
540+
};
541+
542+
let optional_slice = super::SpecialRustType::Option(Box::new(
543+
crate::rust_types::RustType::Special(super::SpecialRustType::Vec(Box::new(
544+
crate::rust_types::RustType::Special(super::SpecialRustType::I32),
545+
))),
546+
));
547+
548+
// by default, optional slices should be translated with a pointer redirection
549+
let go_slice = super::Language::format_special_type(&mut go, &optional_slice, &[]).unwrap();
550+
assert_eq!(go_slice, "*[]int");
551+
552+
// when specifically opting out of this via the config, the pointer redirection should be omitted
553+
go.no_pointer_slice = true;
554+
let go_slice = super::Language::format_special_type(&mut go, &optional_slice, &[]).unwrap();
555+
assert_eq!(go_slice, "[]int");
556+
}
557+
}

0 commit comments

Comments
 (0)