Skip to content

Latest commit

 

History

History
365 lines (329 loc) · 8.25 KB

talk.org

File metadata and controls

365 lines (329 loc) · 8.25 KB

Writing Perl extensions in Rust

Vickenty Fesunov

http://github.com/vickenty/perl-xs

We’re hiring

http://workingatbooking.com

Perl extensions

C is not easy

null pointers

AV* array = get_av("array", 0);
SV** item = av_fetch(array, 0);

dangling pointers

SV** item = av_fetch(array, 0);
av_clear(array);
char *buf = SvPV_nolen(*item);

buffer overflows

char *buf = SvPV_nolen(*item);
sprintf(buf, "%d", rand());

and more

  • uninitialized variables
  • sequence points
  • integer overflows
  • aliasing rules
  • data races

Perl XS API is not easy

What does this function return?

SSize_t av_len(AV* array_ptr);

reference counting

XPUSHs(av_fetch(array, 0))
// but
XPUSHs(sv_2mortal(av_delete(array, 0)))

exceptions

FILE *f = fopen("output", "w");
fprintf(f, "%d", SvIV(value));
fclose(f);

Just be careful?

We must do better.

— Bjarne Stroustrup, 2015

Rust

http://rust-lang.org

  • prevents segfaults
  • compatible with c
  • can do unsafe code if needed
  • safe abstractions

Rust XS

sum array

xs! {
    package Array::Util;

    sub sum_array(ctx, array_ref: SV) {
        let mut sum = 0.0;




        xs_return!(ctx, sum);
    }
}

sum array

xs! {
    package Array::Util;

    sub sum_array(ctx, array_ref: SV) {
        let mut sum = 0.0;
        let array: AV = array_ref.deref_av();



        xs_return!(ctx, 0.0);
    }
}

sum array

xs! {
    package Array::Util;

    sub sum_array(ctx, array_ref: SV) {
        let mut sum = 0.0;
        let array: AV = array_ref.deref_av();
        // ERROR: AV expected, but have Option<AV>


        xs_return!(ctx, 0.0);
    }
}

sum array

xs! {
    package Array::Util;

    sub sum_array(ctx, array_ref: SV) {
        let mut sum = 0.0;
        let array: AV = array_ref.deref_av().expect("an array reference");



        xs_return!(ctx, 0.0);
    }
}

sum array

xs! {
    package Array::Util;

    sub sum_array(ctx, array_ref: SV) {
        let mut sum = 0.0;
        let array: AV = array_ref.deref_av().expect("an array reference");
        for index in 0..array.top_index() + 1 {

        }
        xs_return!(ctx, sum);
    }
}

sum array

xs! {
    package Array::Util;

    sub sum_array(ctx, array_ref: SV) {
        let mut sum = 0.0;
        let array: AV = array_ref.deref_av().expect("an array reference");
        for index in 0..array.top_index() + 1 {
            sum += array.fetch(index);
        }
        xs_return!(ctx, sum);
    }
}

sum array

xs! {
    package Array::Util;

    sub sum_array(ctx, array_ref: SV) {
        let mut sum = 0.0;
        let array: AV = array_ref.deref_av().expect("an array reference");
        for index in 0..array.top_index() + 1 {
            sum += array.fetch(index); // ERROR
        }
        xs_return!(ctx, sum);
    }
}

sum array

xs! {
    package Array::Util;

    sub sum_array(ctx, array_ref: SV) {
        let mut sum = 0.0;
        let array: AV = array_ref.deref_av().expect("an array reference");
        for index in 0..array.top_index() + 1 {
            sum += array.fetch(index).unwrap_or(0.0);
        }
        xs_return!(ctx, sum);
    }
}

sum array, take 2

xs! {
    package Array::Util;

    sub sum_array(ctx, array: AV) {
        let sum


        xs_return!(ctx, sum);
    }
}

sum array, take 2

xs! {
    package Array::Util;

    sub sum_array(ctx, array: AV) {
        let sum: NV = array.iter()


        xs_return!(ctx, sum);
    }
}

sum array, take 2

xs! {
    package Array::Util;

    sub sum_array(ctx, array: AV) {
        let sum: NV = array.iter()
            .map(|v| v.unwrap_or(0.0))

        xs_return!(ctx, sum);
    }
}

sum array, take 2

xs! {
    package Array::Util;

    sub sum_array(ctx, array: AV) {
        let sum: NV = array.iter()
            .map(|v| v.unwrap_or(0.0))
            .sum();
        xs_return!(ctx, sum);
    }
}

Benchmarks

Perl1.003s100%
Rust loop0.645s64%
Rust iter0.637s63%
XS0.164s16%

Why so slow?

  • reference counting
  • no hot path inlining
  • exception handling

exceptions

file:xcpt-2.svg

exceptions

xcpt-3.svg

exceptions

file:xcpt-4.svg

Conclusion

  • it works
  • it is safer
  • it is slower

Thanks

  • Booking.com
  • p5pclub
  • #rust and the Rust community

FIN

xs! {
    package Array::Util;

    sub sum_array(ctx, array: AV) {
        let sum: NV = array.iter()
            .map(|v| v.unwrap_or(0.0))
            .sum();
        xs_return!(ctx, sum);
    }
}

http://github.com/vickenty/perl-xs