Reputation: 29981
I have two &str
pointing to the same string, and I need to know the byte offset between them:
fn main() {
let foo = " bar";
assert_eq!(offset(foo, foo.trim()), Some(2));
let bar = "baz\nquz";
let mut lines = bar.lines();
assert_eq!(offset(bar, lines.next().unwrap()), Some(0));
assert_eq!(offset(bar, lines.next().unwrap()), Some(4));
assert_eq!(offset(foo, bar), None); // not a sub-string
let quz = "quz".to_owned();
assert_eq!(offset(bar, &quz), None); // not the same string, could also return `Some(4)`, I don't care
}
This is basically the same as str::find
, but since the second slice is a sub-slice of the first, I would have hoped something faster. Also str::find
won't work in the lines()
case if several lines are identical.
I thought I could just use some pointer arithmetic to do that with something like foo.trim().as_ptr() - foo.as_ptr()
but it turns out that Sub
is not implemented on raw pointers.
Upvotes: 7
Views: 1443
Reputation: 430310
but it turns out that
Sub
is not implemented on raw pointers.
You can use the offset_from
method:
fn main() {
let source = "hello, world";
let a = &source[1..];
let b = &source[5..];
// I copied this unsafe code from Stack Overflow without
// reading the text that told me how to know if this was safe
let diff = unsafe { b.as_ptr().offset_from(a.as_ptr()) };
println!("{diff}");
}
Please be sure to read the documentation for this method as it describes under what circumstances it will not cause undefined behavior.
In older versions of Rust, you can convert the pointer to a usize
to do math on it:
fn main() {
let source = "hello, world";
let a = &source[1..];
let b = &source[5..];
let diff = b.as_ptr() as usize - a.as_ptr() as usize;
println!("{diff}");
}
Upvotes: 4
Reputation: 71899
This is of course kind of unsafe, but if you want arithmetic, you can just cast the pointers to usize
with as
and subtract that.
(Note: it's not so unsafe that the compiler will actually complain.)
Upvotes: 0