Skip to content

Commit

Permalink
cxx-qt-gen: generate C++ types for Pin<T> correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
ahayzen-kdab committed Dec 13, 2022
1 parent 1186ef0 commit 79190d2
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 10 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Fixed linking Qt with macOS frameworks. This allows using Qt from Homebrew.

### Fixed

- Support for generating correct C++ code for `Pin<T>` Rust types

## [0.4.0](https://github.com/KDAB/cxx-qt/compare/v0.3.0...v0.4.0) - 2022-10-28

### Added
Expand Down
69 changes: 59 additions & 10 deletions crates/cxx-qt-gen/src/generator/cpp/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,34 +86,47 @@ fn generic_argument_to_string(generic: &GenericArgument) -> Result<String> {
}

/// Convert the arguments for a path to C++, eg this is the whole <T> block
fn path_argument_to_string(args: &PathArguments) -> Result<String> {
fn path_argument_to_string(args: &PathArguments) -> Result<Option<Vec<String>>> {
match args {
PathArguments::AngleBracketed(angled) => Ok(format!(
"<{generic_ty}>",
generic_ty = angled
PathArguments::AngleBracketed(angled) => Ok(Some(
angled
.args
.iter()
.map(generic_argument_to_string)
.collect::<Result<Vec<String>>>()?
.join(", ")
.collect::<Result<Vec<String>>>()?,
)),
PathArguments::Parenthesized(_) => Err(Error::new(
args.span(),
"Parenthesized arguments are unsupported",
)),
PathArguments::None => Ok("".to_owned()),
PathArguments::None => Ok(None),
}
}

/// Convert a segment of a path to C++
fn path_segment_to_string(segment: &PathSegment) -> Result<String> {
let args = path_argument_to_string(&segment.arguments)?;
let mut ident = segment.ident.to_string();

// If we are a Pin<T> then for C++ it becomes just T
let args = if ident == "Pin" {
ident = path_argument_to_string(&segment.arguments)?
.map_or_else(|| "".to_owned(), |values| values.join(", "));

None
} else {
path_argument_to_string(&segment.arguments)?.map(|values| values.join(", "))
};

// If there are template args check that we aren't a recognised A of A<B>
if !args.is_empty() {
if args.is_some() {
ident = possible_built_in_template_base(&ident);
}
Ok(format!("{ident}{args}", ident = ident, args = args))

Ok(format!(
"{ident}{args}",
ident = ident,
args = args.map_or_else(|| "".to_owned(), |arg| format!("<{arg}>"))
))
}

/// Convert any built in types to known C++ equivalents
Expand Down Expand Up @@ -239,4 +252,40 @@ mod tests {
let ty = tokens_to_syn(quote! { &mut UniquePtr<QColor> });
assert_eq!(to_cpp_string(&ty).unwrap(), "::std::unique_ptr<QColor>&");
}

#[test]
fn test_to_cpp_string_pin() {
let ty = tokens_to_syn(quote! { Pin<T> });
assert_eq!(to_cpp_string(&ty).unwrap(), "T");
}

#[test]
fn test_to_cpp_string_pin_ref() {
let ty = tokens_to_syn(quote! { Pin<&T> });
assert_eq!(to_cpp_string(&ty).unwrap(), "const T&");
}

#[test]
fn test_to_cpp_string_pin_ref_mut() {
let ty = tokens_to_syn(quote! { Pin<&mut T> });
assert_eq!(to_cpp_string(&ty).unwrap(), "T&");
}

#[test]
fn test_to_cpp_string_pin_template() {
let ty = tokens_to_syn(quote! { Pin<UniquePtr<T>> });
assert_eq!(to_cpp_string(&ty).unwrap(), "::std::unique_ptr<T>");
}

#[test]
fn test_to_cpp_string_pin_template_ref() {
let ty = tokens_to_syn(quote! { Pin<&UniquePtr<T>> });
assert_eq!(to_cpp_string(&ty).unwrap(), "const ::std::unique_ptr<T>&");
}

#[test]
fn test_to_cpp_string_pin_template_ref_mut() {
let ty = tokens_to_syn(quote! { Pin<&mut UniquePtr<T>> });
assert_eq!(to_cpp_string(&ty).unwrap(), "::std::unique_ptr<T>&");
}
}

0 comments on commit 79190d2

Please sign in to comment.