mcarton
mcarton

Reputation: 29981

How to get the byte offset between `&str`

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

Answers (2)

Shepmaster
Shepmaster

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

Sebastian Redl
Sebastian Redl

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

Related Questions