@@ -649,69 +649,162 @@ it exists. The marker is the attribute `#[lang="..."]` and there are
649
649
various different values of ` ... ` , i.e. various different 'lang
650
650
items'.
651
651
652
- For example, ` Box ` pointers require two lang items, one for allocation
653
- and one for deallocation. A freestanding program that uses the ` Box `
654
- sugar for dynamic allocations via ` malloc ` and ` free ` :
652
+ For example, there are lang items related to the implementation of
653
+ string slices (` &str ` ); one of these is ` str_eq ` , which implements the
654
+ equivalence relation on two string slices. This is a lang item because
655
+ string equivalence is used for more than just the ` == ` operator; in
656
+ particular, it is also used when pattern matching string literals.
657
+
658
+ A freestanding program that provides its own definition of the
659
+ ` str_eq ` lang item, with a slightly different semantics than
660
+ usual in Rust:
655
661
656
662
```
657
- #![feature(lang_items, box_syntax , start, no_std)]
663
+ #![feature(lang_items, intrinsics , start, no_std)]
658
664
#![no_std]
659
665
660
- extern crate libc;
666
+ // Our str_eq lang item; it normalizes ASCII letters to lowercase.
667
+ #[lang="str_eq"]
668
+ fn eq_slice(s1: &str, s2: &str) -> bool {
669
+ unsafe {
670
+ let (p1, s1_len) = str::repr(s1);
671
+ let (p2, s2_len) = str::repr(s2);
661
672
662
- extern {
663
- fn abort() -> !;
664
- }
673
+ if s1_len != s2_len { return false; }
674
+
675
+ let mut i = 0;
676
+ while i < s1_len {
677
+ let b1 = str::at_offset(p1, i);
678
+ let b2 = str::at_offset(p2, i);
665
679
666
- #[lang = "owned_box"]
667
- pub struct Box<T>(*mut T );
680
+ let b1 = lower_if_ascii(b1);
681
+ let b2 = lower_if_ascii(b2 );
668
682
669
- #[lang="exchange_malloc"]
670
- unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
671
- let p = libc::malloc(size as libc::size_t) as *mut u8;
683
+ if b1 != b2 { return false; }
672
684
673
- // malloc failed
674
- if p as usize == 0 {
675
- abort();
685
+ i += 1;
686
+ }
676
687
}
677
688
678
- p
679
- }
680
- #[lang="exchange_free"]
681
- unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
682
- libc::free(ptr as *mut libc::c_void)
689
+ return true;
690
+
691
+ fn lower_if_ascii(b: u8) -> u8 {
692
+ if 'A' as u8 <= b && b <= 'Z' as u8 {
693
+ b - ('A' as u8) + ('a' as u8)
694
+ } else {
695
+ b
696
+ }
697
+ }
683
698
}
684
699
685
700
#[start]
686
- fn main(argc: isize, argv: *const *const u8) -> isize {
687
- let x = box 1;
701
+ fn main(_argc: isize, _argv: *const *const u8) -> isize {
702
+ let a = "HELLO\0";
703
+ let b = "World\0";
704
+ unsafe {
705
+ let (a_ptr, b_ptr) = (str::as_bytes(a), str::as_bytes(b));
706
+ match (a,b) {
707
+ ("hello\0", "world\0") => {
708
+ printf::print2p("Whoa; matched \"hello world\" on \"%s, %s\"\n\0",
709
+ a_ptr, b_ptr);
710
+ }
711
+
712
+ ("HELLO\0", "World\0") => {
713
+ printf::print2p("obviously match on %s, %s\n\0", a_ptr, b_ptr);
714
+ }
715
+
716
+ _ => printf::print0("No matches at all???\n\0"),
717
+ }
718
+ }
719
+ return 0;
720
+ }
688
721
689
- 0
722
+ // To be able to print to standard output from this demonstration
723
+ // program, we link with `printf` from the C standard library. Note
724
+ // that this requires we null-terminate our strings with "\0".
725
+ mod printf {
726
+ use super::str;
727
+
728
+ #[link(name="c")]
729
+ extern { fn printf(f: *const u8, ...); }
730
+
731
+ pub unsafe fn print0(s: &str) {
732
+ // guard against failure to include '\0'
733
+ if str::last_byte(s) != '\0' as u8 {
734
+ printf(str::as_bytes("(invalid input str)\n\0"));
735
+ } else {
736
+ let bytes = str::as_bytes(s);
737
+ printf(bytes);
738
+ }
739
+ }
740
+
741
+ pub unsafe fn print2p<T,U>(s: &str, arg1: *const T, arg2: *const U) {
742
+ // guard against failure to include '\0'
743
+ if str::last_byte(s) != '\0' as u8 {
744
+ printf(str::as_bytes("(invalid input str)\n\0"));
745
+ } else {
746
+ let bytes = str::as_bytes(s);
747
+ printf(bytes, arg1, arg2);
748
+ }
749
+ }
750
+ }
751
+
752
+ /// A collection of functions to operate on string slices.
753
+ mod str {
754
+ /// Extracts the underlying representation of a string slice.
755
+ pub unsafe fn repr(s: &str) -> (*const u8, usize) {
756
+ extern "rust-intrinsic" { fn transmute<T,U>(e: T) -> U; }
757
+ transmute(s)
758
+ }
759
+
760
+ /// Extracts the pointer to bytes representing the string slice.
761
+ pub fn as_bytes(s: &str) -> *const u8 {
762
+ unsafe { repr(s).0 }
763
+ }
764
+
765
+ /// Returns the last byte in the string slice.
766
+ pub fn last_byte(s: &str) -> u8 {
767
+ unsafe {
768
+ let (bytes, len): (*const u8, usize) = repr(s);
769
+ at_offset(bytes, len-1)
770
+ }
771
+ }
772
+
773
+ /// Returns the byte at offset `i` in the byte string.
774
+ pub unsafe fn at_offset(p: *const u8, i: usize) -> u8 {
775
+ *((p as usize + i) as *const u8)
776
+ }
690
777
}
691
778
779
+ // Again, these functions and traits are used by the compiler, and are
780
+ // normally provided by libstd. (The `Sized` and `Copy` lang_items
781
+ // require definitions due to the type-parametric code above.)
782
+
692
783
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
693
784
#[lang = "eh_personality"] extern fn eh_personality() {}
694
785
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
786
+
787
+ #[lang="sized"] pub trait Sized: PhantomFn<Self,Self> {}
788
+ #[lang="copy"] pub trait Copy: PhantomFn<Self,Self> {}
789
+ #[lang="phantom_fn"] pub trait PhantomFn<A:?Sized,R:?Sized=()> { }
695
790
```
696
791
697
- Note the use of ` abort ` : the ` exchange_malloc ` lang item is assumed to
698
- return a valid pointer, and so needs to do the check internally.
699
792
700
793
Other features provided by lang items include:
701
794
702
795
- overloadable operators via traits: the traits corresponding to the
703
796
` == ` , ` < ` , dereferencing (` * ` ) and ` + ` (etc.) operators are all
704
797
marked with lang items; those specific four are ` eq ` , ` ord ` ,
705
798
` deref ` , and ` add ` respectively.
706
- - stack unwinding and general failure; the ` eh_personality ` , ` fail `
707
- and ` fail_bounds_checks ` lang items.
799
+ - stack unwinding and general failure; the ` eh_personality ` , ` panic `
800
+ ` panic_fmt ` , and ` panic_bounds_check ` lang items.
708
801
- the traits in ` std::marker ` used to indicate types of
709
802
various kinds; lang items ` send ` , ` sync ` and ` copy ` .
710
803
- the marker types and variance indicators found in
711
804
` std::marker ` ; lang items ` covariant_type ` ,
712
805
` contravariant_lifetime ` , etc.
713
806
714
807
Lang items are loaded lazily by the compiler; e.g. if one never uses
715
- ` Box ` then there is no need to define functions for ` exchange_malloc `
716
- and ` exchange_free ` . ` rustc ` will emit an error when an item is needed
717
- but not found in the current crate or any that it depends on.
808
+ array indexing ( ` a[i] ` ) then there is no need to define a function for
809
+ ` panic_bounds_check ` . ` rustc ` will emit an error when an item is
810
+ needed but not found in the current crate or any that it depends on.
0 commit comments