Skip to content

Commit

Permalink
Improve logic for computing paths to relative files for C++
Browse files Browse the repository at this point in the history
  • Loading branch information
Walter-Reactor committed Jan 22, 2025
1 parent 82132cf commit e6ef3e4
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 32 deletions.
38 changes: 38 additions & 0 deletions feature_tests/cpp/include/nested/ns/Nested.d.hpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions feature_tests/cpp/include/nested/ns/Nested.hpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 38 additions & 0 deletions feature_tests/cpp/include/nested/ns2/Nested.d.hpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions feature_tests/cpp/include/nested/ns2/Nested.hpp

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions feature_tests/cpp/tests/attrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@
#include "../include/ns/AttrOpaque1Renamed.hpp"
#include "../include/ns/RenamedAttrEnum.hpp"
#include "../include/Unnamespaced.hpp"
#include "../include/nested/ns/Nested.hpp"
#include "../include/nested/ns2/Nested.hpp"
#include "assert.hpp"

int main(int argc, char *argv[]) {
int main(int argc, char *argv[])
{
std::unique_ptr<ns::AttrOpaque1Renamed> r = ns::AttrOpaque1Renamed::totally_not_new();
simple_assert_eq("method should call", r->method_renamed(), 77);
simple_assert_eq("method should call", r->abirenamed(), 123);

// These C names should also resolve
void* renamed = (void*)ns::capi::renamed_on_abi_only;
std::cout<<"Renamed function at "<<renamed<<std::endl;
renamed = (void*)ns::capi::namespace_AttrOpaque1_method;
std::cout<<"Renamed function at "<<renamed<<std::endl;
void *renamed = (void *)ns::capi::renamed_on_abi_only;
std::cout << "Renamed function at " << renamed << std::endl;
renamed = (void *)ns::capi::namespace_AttrOpaque1_method;
std::cout << "Renamed function at " << renamed << std::endl;

ns::RenamedAttrEnum e = ns::RenamedAttrEnum::A;

Expand Down
10 changes: 10 additions & 0 deletions feature_tests/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ pub mod ffi {
pub fn use_namespaced(&self, _n: &AttrOpaque1) {}
}

#[diplomat::opaque]
#[diplomat::attr(auto, namespace = "nested::ns")]
#[diplomat::attr(not(kotlin), rename = "Nested")]
pub struct Nested;

#[diplomat::opaque]
#[diplomat::attr(auto, namespace = "nested::ns2")]
#[diplomat::attr(not(kotlin), rename = "Nested")]
pub struct Nested2;

#[diplomat::opaque]
#[diplomat::attr(not(supports = comparators), disable)]
pub struct Comparable(u8);
Expand Down
4 changes: 2 additions & 2 deletions tool/src/cpp/formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl<'tcx> Cpp2Formatter<'tcx> {
.rename
.apply(resolved.name().as_str().into());
if let Some(ref ns) = resolved.attrs().namespace {
let ns = ns.replace("::", std::path::MAIN_SEPARATOR_STR);
let ns = ns.replace("::", "/");
format!("{ns}/{type_name}.d.hpp")
} else {
format!("{type_name}.d.hpp")
Expand All @@ -71,7 +71,7 @@ impl<'tcx> Cpp2Formatter<'tcx> {
.rename
.apply(resolved.name().as_str().into());
if let Some(ref ns) = resolved.attrs().namespace {
let ns = ns.replace("::", std::path::MAIN_SEPARATOR_STR);
let ns = ns.replace("::", "/");
format!("{ns}/{type_name}.hpp")
} else {
format!("{type_name}.hpp")
Expand Down
84 changes: 59 additions & 25 deletions tool/src/cpp/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,31 +143,7 @@ impl fmt::Display for Header {
includes: self
.includes
.iter()
.map(|s| {
if let Some((ns, _)) = self.path.split_once('/') {
if let Some((other_ns, file)) = s.split_once('/') {
if ns == other_ns {
Cow::Borrowed(file)
} else {
Cow::Owned(format!(
"{}{s}",
"../".repeat(
s.chars().filter(|c| *c == '/' || *c == '\\').count() + 1
)
))
}
} else {
Cow::Owned(format!(
"{}{s}",
"../".repeat(
ns.chars().filter(|c| *c == '/' || *c == '\\').count() + 1
)
))
}
} else {
Cow::Borrowed(s.as_str())
}
})
.map(|s| get_relative_path(&self.path, s))
.collect(),
forwards: &self.forwards,
body,
Expand All @@ -177,3 +153,61 @@ impl fmt::Display for Header {
f.write_char('\n')
}
}

// As rsplit_once, except the first of the tuple will include the delimiter pattern
fn rsplit_once_inclusive(str: &str, delim: char) -> Option<(&str, &str)> {
str.rfind(delim).map(|i| str.split_at(i + 1))
}

/// Returns the path to 'other' along with the # of steps back from 'root' required
///
/// e.g get_nearest_root("/a/b/c/d.hpp", "a/b/z/d.hpp") -> "z/d.hpp", 2
/// or get_nearest_root("a/b.hpp", "root.hpp") -> "root.hpp", 1
fn get_relative_path<'a>(base: &'a str, path: &'a str) -> Cow<'a, str> {
let (mut base_ns, _) = rsplit_once_inclusive(base, '/').unwrap_or(("", base));
let (mut path_ns, file) = rsplit_once_inclusive(path, '/').unwrap_or(("", path));

let mut matching_chars = 0;
// Consume and count the length of the matching section
loop {
let b = base_ns.split_once('/');
let p = path_ns.split_once('/');
if let (Some(b), Some(p)) = (b, p) {
if b.0 == p.0 {
base_ns = b.1;
path_ns = p.1;
matching_chars += b.0.len() + 1; // 1 for the consumed delimiter
continue;
}
}
break;
}

// Base has run out without a mismatch, the relative path is a strict subset of path & can be borrowed
if base_ns.len() == 0 {
return path.split_at(matching_chars).1.into();
} else {
let up_dirs = base_ns.matches('/').count();
return ("../".repeat(up_dirs) + path_ns + file).into();
}
}

#[test]
fn test_get_relative_path() {
let a = "a/same.hpp";
let b = "a/same2.hpp";
assert_eq!(get_relative_path(a, b), "same2.hpp");

let a = "root.hpp";
let b = "a/nested.hpp";
assert_eq!(get_relative_path(a, b), "a/nested.hpp");

let a = "a/nested.hpp";
let b = "root.hpp";
assert_eq!(get_relative_path(a, b), "../root.hpp");

let a = "a/b/c/d.hpp";
let b = "a/b/z/c/d.hpp";

assert_eq!(get_relative_path(a, b), "../z/c/d.hpp");
}

0 comments on commit e6ef3e4

Please sign in to comment.