<commit_before>extern crate rand;

const FEMALE_NAMES: &'static [&str] = &[
    "Lily", "Phillys", "Ruth", "Adrienne",
    "Jennifer", "Amy", "Melissa", "Michelle",
    "Kimberly", "Lisa", "Angela", "Heather",
    "Stephanie", "Nicole", "Jessica", "Elizabeth",
    "Rebecca", "Kelly", "Mary", "Christina",
    "Amanda", "Julie", "Sarah", "Laura",
    "Shannon", "Christine", "Tammy", "Tracy",
    "Karen", "Dawn", "Susan", "Andrea",
    "Tina", "Patricia", "Cynthia", "Lori",
    "Rachel", "April", "Maria", "Wendy",
    "Crystal", "Stacy", "Erin", "Jamie",
    "Carrie", "Tiffany", "Tara", "Sandra",
    "Monica", "Danielle", "Stacey", "Pamela",
    "Tonya", "Sara", "Michele", "Teresa",
    "Denise", "Jill", "Katherine", "Melanie",
    "Dana", "Holly", "Erica", "Brenda",
    "Deborah", "Tanya", "Sharon", "Donna",
    "Amber", "Emily", "Robin", "Linda",
    "Kathleen", "Leslie", "Christy", "Kristen",
    "Catherine", "Kristin", "Misty", "Barbara",
    "Heidi", "Nancy", "Cheryl", "Theresa",
    "Brandy", "Alicia", "Veronica", "Gina",
    "Jacqueline", "Rhonda", "Anna", "Renee",
    "Megan", "Tamara", "Melinda", "Kathryn",
    "Debra", "Sherry", "Allison", "Valerie",
    "Diana", "Paula", "Kristina", "Ann",
    "Margaret", "Cindy", "Victoria", "Jodi",
    "Natalie", "Brandi", "Suzanne", "Kristi",
    "Samantha", "Beth", "Tracey", "Regina",
    "Vanessa", "Kristy", "Carolyn", "Yolanda",
    "Deanna", "Carla", "Sheila", "Laurie",
    "Anne", "Shelly", "Diane", "Sabrina",
    "Janet", "Erika", "Katrina", "Courtney",
    "Colleen", "Carol", "Julia", "Jenny",
    "Jaime", "Kathy", "Felicia", "Alison",
    "Lauren", "Kelli", "Leah", "Ashley",
    "Kim", "Traci", "Kristine", "Tricia",
    "Joy", "Krista", "Kara", "Terri",
    "Sonya", "Aimee", "Natasha", "Cassandra",
    "Bridget", "Anita", "Kari", "Nichole",
    "Christie", "Marie", "Virginia", "Connie",
    "Martha", "Carmen", "Stacie", "Lynn",
    "Katie", "Monique", "Kristie", "Shelley",
    "Sherri", "Angel", "Bonnie", "Mandy",
    "Jody", "Shawna", "Kerry", "Annette",
    "Yvonne", "Toni", "Meredith", "Molly",
    "Kendra", "Joanna", "Sonia", "Janice",
    "Robyn", "Brooke", "Kerri", "Sheri",
    "Becky", "Gloria", "Mindy", "Tracie",
    "Angie", "Kellie", "Claudia", "Ruth",
    "Wanda", "Jeanette", "Cathy",
];

const MALE_NAMES: &'static [&str] = &[
    "Bob", "Ted", "Cletus", "Michael",
    "Christopher", "Jason", "David", "James",
    "John", "Robert", "Brian", "William",
    "Matthew", "Joseph", "Daniel", "Kevin",
    "Eric", "Jeffrey", "Richard", "Scott",
    "Mark", "Steven", "Thomas", "Timothy",
    "Anthony", "Charles", "Joshua", "Ryan",
    "Jeremy", "Paul", "Andrew", "Gregory",
    "Chad", "Kenneth", "Jonathan", "Stephen",
    "Shawn", "Aaron", "Adam", "Patrick",
    "Justin", "Sean", "Edward", "Todd",
    "Donald", "Ronald", "Benjamin", "Keith",
    "Bryan", "Gary", "Jose", "Nathan",
    "Douglas", "Brandon", "Nicholas", "George",
    "Travis", "Peter", "Craig", "Bradley",
    "Larry", "Dennis", "Shane", "Raymond",
    "Troy", "Jerry", "Samuel", "Frank",
    "Jesse", "Jeffery", "Juan", "Terry",
    "Corey", "Phillip", "Marcus", "Derek",
    "Rodney", "Joel", "Carlos", "Randy",
    "Jacob", "Jamie", "Tony", "Russell",
    "Brent", "Antonio", "Billy", "Derrick",
    "Kyle", "Erik", "Johnny", "Marc",
    "Carl", "Philip", "Roger", "Bobby",
    "Brett", "Danny", "Curtis", "Jon",
    "Vincent", "Cory", "Jimmy", "Victor",
    "Lawrence", "Dustin", "Gerald", "Walter",
    "Alexander", "Joe", "Christian", "Chris",
    "Alan", "Shannon", "Wayne", "Jared",
    "Gabriel", "Martin", "Jay", "Luis",
    "Willie", "Micheal", "Henry", "Wesley",
    "Randall", "Brad", "Darren", "Roy",
    "Albert", "Arthur", "Ricky", "Lance",
    "Allen", "Lee", "Bruce", "Andre",
    "Mario", "Frederick", "Louis", "Darrell",
    "Damon", "Shaun", "Nathaniel", "Zachary",
    "Casey", "Adrian", "Jesus", "Jeremiah",
    "Jack", "Ronnie", "Dale", "Tyrone",
    "Manuel", "Ricardo", "Harold", "Kelly",
    "Barry", "Ian", "Reginald", "Glenn",
    "Ernest", "Steve", "Seth", "Eugene",
    "Clinton", "Miguel", "Tommy", "Eddie",
    "Leonard", "Maurice", "Roberto", "Dwayne",
    "Jerome", "Ralph", "Marvin", "Francisco",
    "Jorge", "Neil", "Alex", "Dean",
    "Kristopher", "Calvin", "Kurt", "Theodore",
    "Ruben", "Jermaine", "Tracy", "Edwin",
    "Stanley", "Melvin", "Howard", "Mitchell",
    "Duane", "Trevor", "Jeff", "Geoffrey",
    "Hector", "Terrence", "Terrance", "Oscar",
    "Jaime", "Clifford", "Harry",
];

pub struct NameGenerator;

impl NameGenerator {
    pub fn gen_female() -> String {
        let idx = rand::random::<usize>() % FEMALE_NAMES.len();

        String::from(FEMALE_NAMES[idx])
    }

    pub fn gen_male() -> String {
        let idx = rand::random::<usize>() % MALE_NAMES.len();

        String::from(MALE_NAMES[idx])
    }

    pub fn gen_name() -> String {
        if rand::random::<bool>() {
            Self::gen_female()
        } else {
            Self::gen_male()
        }
    }
}

<commit_msg>replace duplicate name in name_generator<commit_after>extern crate rand;

const FEMALE_NAMES: &'static [&str] = &[
    "Lily", "Phillys", "Agnes", "Adrienne",
    "Jennifer", "Amy", "Melissa", "Michelle",
    "Kimberly", "Lisa", "Angela", "Heather",
    "Stephanie", "Nicole", "Jessica", "Elizabeth",
    "Rebecca", "Kelly", "Mary", "Christina",
    "Amanda", "Julie", "Sarah", "Laura",
    "Shannon", "Christine", "Tammy", "Tracy",
    "Karen", "Dawn", "Susan", "Andrea",
    "Tina", "Patricia", "Cynthia", "Lori",
    "Rachel", "April", "Maria", "Wendy",
    "Crystal", "Stacy", "Erin", "Jamie",
    "Carrie", "Tiffany", "Tara", "Sandra",
    "Monica", "Danielle", "Stacey", "Pamela",
    "Tonya", "Sara", "Michele", "Teresa",
    "Denise", "Jill", "Katherine", "Melanie",
    "Dana", "Holly", "Erica", "Brenda",
    "Deborah", "Tanya", "Sharon", "Donna",
    "Amber", "Emily", "Robin", "Linda",
    "Kathleen", "Leslie", "Christy", "Kristen",
    "Catherine", "Kristin", "Misty", "Barbara",
    "Heidi", "Nancy", "Cheryl", "Theresa",
    "Brandy", "Alicia", "Veronica", "Gina",
    "Jacqueline", "Rhonda", "Anna", "Renee",
    "Megan", "Tamara", "Melinda", "Kathryn",
    "Debra", "Sherry", "Allison", "Valerie",
    "Diana", "Paula", "Kristina", "Ann",
    "Margaret", "Cindy", "Victoria", "Jodi",
    "Natalie", "Brandi", "Suzanne", "Kristi",
    "Samantha", "Beth", "Tracey", "Regina",
    "Vanessa", "Kristy", "Carolyn", "Yolanda",
    "Deanna", "Carla", "Sheila", "Laurie",
    "Anne", "Shelly", "Diane", "Sabrina",
    "Janet", "Erika", "Katrina", "Courtney",
    "Colleen", "Carol", "Julia", "Jenny",
    "Jaime", "Kathy", "Felicia", "Alison",
    "Lauren", "Kelli", "Leah", "Ashley",
    "Kim", "Traci", "Kristine", "Tricia",
    "Joy", "Krista", "Kara", "Terri",
    "Sonya", "Aimee", "Natasha", "Cassandra",
    "Bridget", "Anita", "Kari", "Nichole",
    "Christie", "Marie", "Virginia", "Connie",
    "Martha", "Carmen", "Stacie", "Lynn",
    "Katie", "Monique", "Kristie", "Shelley",
    "Sherri", "Angel", "Bonnie", "Mandy",
    "Jody", "Shawna", "Kerry", "Annette",
    "Yvonne", "Toni", "Meredith", "Molly",
    "Kendra", "Joanna", "Sonia", "Janice",
    "Robyn", "Brooke", "Kerri", "Sheri",
    "Becky", "Gloria", "Mindy", "Tracie",
    "Angie", "Kellie", "Claudia", "Ruth",
    "Wanda", "Jeanette", "Cathy",
];

const MALE_NAMES: &'static [&str] = &[
    "Bob", "Ted", "Cletus", "Michael",
    "Christopher", "Jason", "David", "James",
    "John", "Robert", "Brian", "William",
    "Matthew", "Joseph", "Daniel", "Kevin",
    "Eric", "Jeffrey", "Richard", "Scott",
    "Mark", "Steven", "Thomas", "Timothy",
    "Anthony", "Charles", "Joshua", "Ryan",
    "Jeremy", "Paul", "Andrew", "Gregory",
    "Chad", "Kenneth", "Jonathan", "Stephen",
    "Shawn", "Aaron", "Adam", "Patrick",
    "Justin", "Sean", "Edward", "Todd",
    "Donald", "Ronald", "Benjamin", "Keith",
    "Bryan", "Gary", "Jose", "Nathan",
    "Douglas", "Brandon", "Nicholas", "George",
    "Travis", "Peter", "Craig", "Bradley",
    "Larry", "Dennis", "Shane", "Raymond",
    "Troy", "Jerry", "Samuel", "Frank",
    "Jesse", "Jeffery", "Juan", "Terry",
    "Corey", "Phillip", "Marcus", "Derek",
    "Rodney", "Joel", "Carlos", "Randy",
    "Jacob", "Jamie", "Tony", "Russell",
    "Brent", "Antonio", "Billy", "Derrick",
    "Kyle", "Erik", "Johnny", "Marc",
    "Carl", "Philip", "Roger", "Bobby",
    "Brett", "Danny", "Curtis", "Jon",
    "Vincent", "Cory", "Jimmy", "Victor",
    "Lawrence", "Dustin", "Gerald", "Walter",
    "Alexander", "Joe", "Christian", "Chris",
    "Alan", "Shannon", "Wayne", "Jared",
    "Gabriel", "Martin", "Jay", "Luis",
    "Willie", "Micheal", "Henry", "Wesley",
    "Randall", "Brad", "Darren", "Roy",
    "Albert", "Arthur", "Ricky", "Lance",
    "Allen", "Lee", "Bruce", "Andre",
    "Mario", "Frederick", "Louis", "Darrell",
    "Damon", "Shaun", "Nathaniel", "Zachary",
    "Casey", "Adrian", "Jesus", "Jeremiah",
    "Jack", "Ronnie", "Dale", "Tyrone",
    "Manuel", "Ricardo", "Harold", "Kelly",
    "Barry", "Ian", "Reginald", "Glenn",
    "Ernest", "Steve", "Seth", "Eugene",
    "Clinton", "Miguel", "Tommy", "Eddie",
    "Leonard", "Maurice", "Roberto", "Dwayne",
    "Jerome", "Ralph", "Marvin", "Francisco",
    "Jorge", "Neil", "Alex", "Dean",
    "Kristopher", "Calvin", "Kurt", "Theodore",
    "Ruben", "Jermaine", "Tracy", "Edwin",
    "Stanley", "Melvin", "Howard", "Mitchell",
    "Duane", "Trevor", "Jeff", "Geoffrey",
    "Hector", "Terrence", "Terrance", "Oscar",
    "Jaime", "Clifford", "Harry",
];

pub struct NameGenerator;

impl NameGenerator {
    pub fn gen_female() -> String {
        let idx = rand::random::<usize>() % FEMALE_NAMES.len();

        String::from(FEMALE_NAMES[idx])
    }

    pub fn gen_male() -> String {
        let idx = rand::random::<usize>() % MALE_NAMES.len();

        String::from(MALE_NAMES[idx])
    }

    pub fn gen_name() -> String {
        if rand::random::<bool>() {
            Self::gen_female()
        } else {
            Self::gen_male()
        }
    }
}

<|endoftext|>


<commit_before>use io::MBuf;
use std::ptr;
use std::marker::PhantomData;
use std::slice;
use headers::{EndOffset, NullHeader};
// Some low level functions.
#[link(name = "zcsi")]
extern "C" {
    fn mbuf_alloc() -> *mut MBuf;
    fn mbuf_free(buf: *mut MBuf);
    fn mbuf_alloc_bulk(array: *mut *mut MBuf, len: u16, cnt: i32) -> i32;
}

/// A packet is a safe wrapper around mbufs, that can be allocated and manipulated.
/// We associate a header type with a packet to allow safe insertion of headers.
pub struct Packet<T: EndOffset> {
    mbuf: *mut MBuf,
    _phantom_t: PhantomData<T>,
}

fn reference_mbuf(mbuf: *mut MBuf) {
    unsafe { (*mbuf).reference() };
}

const HEADER_SLOT: usize = 0;
const OFFSET_SLOT: usize = 1;

pub fn packet_from_mbuf<T:EndOffset>(mbuf: *mut MBuf, offset: usize) -> Packet<T> {
        // Need to up the refcnt, so that things don't drop.
        reference_mbuf(mbuf);
        packet_from_mbuf_no_increment(mbuf, offset)
}

pub fn packet_from_mbuf_no_increment<T:EndOffset>(mbuf: *mut MBuf, offset: usize) -> Packet<T> {
    unsafe {
        // Compute the real offset
        let header =  (*mbuf).data_address(offset) as *mut T;
        let mut pkt = Packet::<T> {
            mbuf: mbuf,
            _phantom_t: PhantomData,
        };
        pkt.update_ptrs(header as *mut u8, offset);
        pkt
    }
}

pub unsafe fn packet_from_mbuf_no_free<T:EndOffset>(mbuf: *mut MBuf, offset: usize) -> Packet<T> {
        // Compute the real offset
        let header =  (*mbuf).data_address(offset) as *mut T;
        let mut pkt = Packet::<T> {
            mbuf: mbuf,
            _phantom_t: PhantomData,
        };
        pkt.update_ptrs(header as *mut u8, offset);
        pkt
}

/// Allocate a new packet.
pub fn new_packet() -> Option<Packet<NullHeader>> {
    unsafe {
        // This sets refcnt = 1
        let mbuf = mbuf_alloc();
        if mbuf.is_null() {
            None
        } else {
            let header = (*mbuf).data_address(0);
            let mut pkt = Packet {
                mbuf: mbuf,
                _phantom_t: PhantomData,
            };
            pkt.update_ptrs(header, 0);
            Some(pkt)
        }
    }
}

pub fn new_packet_array(count: usize) -> Vec<Packet<NullHeader>> {
    let mut array = Vec::with_capacity(count);
    unsafe {
        let alloc_ret = mbuf_alloc_bulk(array.as_mut_ptr(), 0, count as i32);
        if alloc_ret == 0 {
            array.set_len(count);
        }
    }
    array.iter().map(|m| packet_from_mbuf_no_increment(m.clone(), 0)).collect()
}

pub const METADATA_SLOTS : u16 = 8;

impl<T: EndOffset> Packet<T> {
    #[inline]
    pub fn free_packet(self) {
        if !self.mbuf.is_null() {
            unsafe { mbuf_free(self.mbuf) };
        }
    }

    #[inline]
    fn update_ptrs(&mut self, header: *mut u8, offset: usize) {
        MBuf::write_metadata_slot(self.mbuf, HEADER_SLOT, header as usize);
        MBuf::write_metadata_slot(self.mbuf, OFFSET_SLOT, offset as usize);
    }

    #[inline]
    fn header(&self) -> *mut T {
        MBuf::read_metadata_slot(self.mbuf, HEADER_SLOT) as *mut T
    }

    #[inline]
    fn header_u8(&self) -> *mut u8 {
        MBuf::read_metadata_slot(self.mbuf, HEADER_SLOT) as *mut u8
    }

    #[inline]
    fn payload(&self) -> *mut u8 {
        unsafe {
            let payload_offset = self.payload_offset();
            self.header_u8().offset(payload_offset as isize)
        }
    }

    #[inline]
    fn offset(&self) -> usize {
        MBuf::read_metadata_slot(self.mbuf, OFFSET_SLOT)
    }

    #[inline]
    fn payload_offset(&self) -> usize {
        unsafe { (*self.header()).offset() }
    }

    #[inline]
    fn data_base(&self) -> *mut u8 {
        unsafe { (*self.mbuf).data_address(0) }
    }

    #[inline]
    fn data_len(&self) -> usize {
        unsafe { (*self.mbuf).data_len() }
    }

    #[inline]
    fn payload_size(&self) -> usize {
        self.data_len() - self.offset()
    }

    #[inline]
    pub fn get_header(&self) -> &T {
        unsafe { &(*(self.header())) }
    }

    #[inline]
    pub fn get_mut_header(&mut self) -> &mut T {
        unsafe { &mut (*(self.header())) }
    }

    pub fn push_header<T2: EndOffset<PreviousHeader = T>>(mut self, header: &T2) -> Option<Packet<T2>> {
        unsafe {
            let len = self.data_len();
            let size = header.offset();
            let added = (*self.mbuf).add_data_end(size);

            let header = self.payload();

            let hdr = header as *mut T2;
            let offset = self.payload_offset();
            if added >= size {
                let dst = if len != offset {
                    // Need to move down the rest of the data down.
                    let final_dst = self.payload();
                    let move_loc = final_dst.offset(size as isize);
                    let to_move = len - offset;
                    ptr::copy_nonoverlapping(final_dst, move_loc, to_move);
                    final_dst as *mut T2
                } else {
                    self.payload() as *mut T2
                };
                ptr::copy_nonoverlapping(hdr, dst, 1);
                self.update_ptrs(header, offset);
                Some(Packet {
                    mbuf: self.get_mbuf(),
                    _phantom_t: PhantomData,
                })
            } else {
                None
            }
        }
    }

    #[inline]
    pub fn parse_header<T2: EndOffset<PreviousHeader = T>>(mut self) -> Packet<T2> {
        unsafe {
            let hdr = self.payload();
            let offset = self.payload_offset();
            self.update_ptrs(hdr, offset);
            Packet {
                mbuf: self.get_mbuf(),
                _phantom_t: PhantomData,
            }
        }
    }

    #[inline]
    pub fn deparse_header(mut self, offset: usize) -> Packet<T::PreviousHeader> {
        let offset = offset as isize;
        unsafe {
            let header = self.header_u8().offset(-offset);
            //let payload = self.payload().offset(-offset);
            let new_offset = self.offset() - offset as usize;
            self.update_ptrs(header, new_offset);
            Packet {
                mbuf: self.get_mbuf(),
                _phantom_t: PhantomData,
            }
        }
    }

    #[inline]
    pub fn reset(mut self) -> Packet<NullHeader> {
        unsafe {
            let addr = self.data_base();
            self.update_ptrs(addr, 0);
            let mbuf = self.get_mbuf();
            Packet {
                mbuf: mbuf,
                _phantom_t: PhantomData,
            }
        }
    }

    #[inline]
    pub fn get_mut_payload(&mut self) -> &mut [u8] {
        unsafe {
            let len = self.payload_size();
            let ptr = self.payload();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    #[inline]
    pub fn get_payload(&self) -> &[u8] {
        unsafe {
            let len = self.payload_size();
            slice::from_raw_parts(self.payload(), len)
        }
    }

    #[inline]
    pub fn increase_payload_size(&mut self, increase_by: usize) -> usize {
        unsafe { (*self.mbuf).add_data_end(increase_by) }
    }

    #[inline]
    pub fn trim_payload_size(&mut self, trim_by: usize) -> usize {
        unsafe { (*self.mbuf).remove_data_end(trim_by) }
    }

    #[inline]
    pub fn copy_payload(&mut self, other: &Self) -> usize {
        let copy_len = other.payload_size();
        let dst = self.payload();
        let src = other.payload();

        let payload_size = self.payload_size();

        let should_copy = if payload_size < copy_len {
            let increment = copy_len - payload_size;
            self.increase_payload_size(increment)
        } else {
            copy_len
        };

        unsafe {
            ptr::copy_nonoverlapping(src, dst, should_copy);
            should_copy
        }
    }

    #[inline]
    pub fn refcnt(&self) -> u16 {
        unsafe { (*self.mbuf).refcnt() }
    }

    /// Get the mbuf reference by this packet.
    ///
    /// # Safety
    /// The reference held by this Packet is nulled out as a result of this code. The callee is responsible for
    /// appropriately freeing this mbuf from here-on out.
    #[inline]
    pub unsafe fn get_mbuf(&mut self) -> *mut MBuf {
        let mbuf = self.mbuf;
        self.mbuf = ptr::null_mut();
        mbuf
    }
}
<commit_msg>Fix offset for packet<commit_after>use io::MBuf;
use std::ptr;
use std::marker::PhantomData;
use std::slice;
use headers::{EndOffset, NullHeader};
// Some low level functions.
#[link(name = "zcsi")]
extern "C" {
    fn mbuf_alloc() -> *mut MBuf;
    fn mbuf_free(buf: *mut MBuf);
    fn mbuf_alloc_bulk(array: *mut *mut MBuf, len: u16, cnt: i32) -> i32;
}

/// A packet is a safe wrapper around mbufs, that can be allocated and manipulated.
/// We associate a header type with a packet to allow safe insertion of headers.
pub struct Packet<T: EndOffset> {
    mbuf: *mut MBuf,
    _phantom_t: PhantomData<T>,
}

fn reference_mbuf(mbuf: *mut MBuf) {
    unsafe { (*mbuf).reference() };
}

const HEADER_SLOT: usize = 0;
const OFFSET_SLOT: usize = 1;

pub fn packet_from_mbuf<T:EndOffset>(mbuf: *mut MBuf, offset: usize) -> Packet<T> {
        // Need to up the refcnt, so that things don't drop.
        reference_mbuf(mbuf);
        packet_from_mbuf_no_increment(mbuf, offset)
}

pub fn packet_from_mbuf_no_increment<T:EndOffset>(mbuf: *mut MBuf, offset: usize) -> Packet<T> {
    unsafe {
        // Compute the real offset
        let header =  (*mbuf).data_address(offset) as *mut T;
        let mut pkt = Packet::<T> {
            mbuf: mbuf,
            _phantom_t: PhantomData,
        };
        pkt.update_ptrs(header as *mut u8, offset);
        pkt
    }
}

pub unsafe fn packet_from_mbuf_no_free<T:EndOffset>(mbuf: *mut MBuf, offset: usize) -> Packet<T> {
        // Compute the real offset
        let header =  (*mbuf).data_address(offset) as *mut T;
        let mut pkt = Packet::<T> {
            mbuf: mbuf,
            _phantom_t: PhantomData,
        };
        pkt.update_ptrs(header as *mut u8, offset);
        pkt
}

/// Allocate a new packet.
pub fn new_packet() -> Option<Packet<NullHeader>> {
    unsafe {
        // This sets refcnt = 1
        let mbuf = mbuf_alloc();
        if mbuf.is_null() {
            None
        } else {
            let header = (*mbuf).data_address(0);
            let mut pkt = Packet {
                mbuf: mbuf,
                _phantom_t: PhantomData,
            };
            pkt.update_ptrs(header, 0);
            Some(pkt)
        }
    }
}

pub fn new_packet_array(count: usize) -> Vec<Packet<NullHeader>> {
    let mut array = Vec::with_capacity(count);
    unsafe {
        let alloc_ret = mbuf_alloc_bulk(array.as_mut_ptr(), 0, count as i32);
        if alloc_ret == 0 {
            array.set_len(count);
        }
    }
    array.iter().map(|m| packet_from_mbuf_no_increment(m.clone(), 0)).collect()
}

pub const METADATA_SLOTS : u16 = 8;

impl<T: EndOffset> Packet<T> {
    #[inline]
    pub fn free_packet(self) {
        if !self.mbuf.is_null() {
            unsafe { mbuf_free(self.mbuf) };
        }
    }

    #[inline]
    fn update_ptrs(&mut self, header: *mut u8, offset: usize) {
        MBuf::write_metadata_slot(self.mbuf, HEADER_SLOT, header as usize);
        MBuf::write_metadata_slot(self.mbuf, OFFSET_SLOT, offset as usize);
    }

    #[inline]
    fn header(&self) -> *mut T {
        MBuf::read_metadata_slot(self.mbuf, HEADER_SLOT) as *mut T
    }

    #[inline]
    fn header_u8(&self) -> *mut u8 {
        MBuf::read_metadata_slot(self.mbuf, HEADER_SLOT) as *mut u8
    }

    #[inline]
    fn payload(&self) -> *mut u8 {
        unsafe {
            let payload_offset = self.payload_offset();
            self.header_u8().offset(payload_offset as isize)
        }
    }

    #[inline]
    fn offset(&self) -> usize {
        MBuf::read_metadata_slot(self.mbuf, OFFSET_SLOT)
    }

    #[inline]
    fn payload_offset(&self) -> usize {
        unsafe { (*self.header()).offset() }
    }

    #[inline]
    fn data_base(&self) -> *mut u8 {
        unsafe { (*self.mbuf).data_address(0) }
    }

    #[inline]
    fn data_len(&self) -> usize {
        unsafe { (*self.mbuf).data_len() }
    }

    #[inline]
    fn payload_size(&self) -> usize {
        self.data_len() - self.offset()
    }

    #[inline]
    pub fn get_header(&self) -> &T {
        unsafe { &(*(self.header())) }
    }

    #[inline]
    pub fn get_mut_header(&mut self) -> &mut T {
        unsafe { &mut (*(self.header())) }
    }

    pub fn push_header<T2: EndOffset<PreviousHeader = T>>(mut self, header: &T2) -> Option<Packet<T2>> {
        unsafe {
            let len = self.data_len();
            let size = header.offset();
            let added = (*self.mbuf).add_data_end(size);

            let header = self.payload();

            let hdr = header as *mut T2;
            let offset = self.offset() + self.payload_offset();
            if added >= size {
                let dst = if len != offset {
                    // Need to move down the rest of the data down.
                    let final_dst = self.payload();
                    let move_loc = final_dst.offset(size as isize);
                    let to_move = len - offset;
                    ptr::copy_nonoverlapping(final_dst, move_loc, to_move);
                    final_dst as *mut T2
                } else {
                    self.payload() as *mut T2
                };
                ptr::copy_nonoverlapping(hdr, dst, 1);
                self.update_ptrs(header, offset);
                Some(Packet {
                    mbuf: self.get_mbuf(),
                    _phantom_t: PhantomData,
                })
            } else {
                None
            }
        }
    }

    #[inline]
    pub fn parse_header<T2: EndOffset<PreviousHeader = T>>(mut self) -> Packet<T2> {
        unsafe {
            let hdr = self.payload();
            let offset = self.offset() + self.payload_offset();
            self.update_ptrs(hdr, offset);
            Packet {
                mbuf: self.get_mbuf(),
                _phantom_t: PhantomData,
            }
        }
    }

    #[inline]
    pub fn deparse_header(mut self, offset: usize) -> Packet<T::PreviousHeader> {
        let offset = offset as isize;
        unsafe {
            let header = self.header_u8().offset(-offset);
            //let payload = self.payload().offset(-offset);
            let new_offset = self.offset() - offset as usize;
            self.update_ptrs(header, new_offset);
            Packet {
                mbuf: self.get_mbuf(),
                _phantom_t: PhantomData,
            }
        }
    }

    #[inline]
    pub fn reset(mut self) -> Packet<NullHeader> {
        unsafe {
            let addr = self.data_base();
            self.update_ptrs(addr, 0);
            let mbuf = self.get_mbuf();
            Packet {
                mbuf: mbuf,
                _phantom_t: PhantomData,
            }
        }
    }

    #[inline]
    pub fn get_mut_payload(&mut self) -> &mut [u8] {
        unsafe {
            let len = self.payload_size();
            let ptr = self.payload();
            slice::from_raw_parts_mut(ptr, len)
        }
    }

    #[inline]
    pub fn get_payload(&self) -> &[u8] {
        unsafe {
            let len = self.payload_size();
            slice::from_raw_parts(self.payload(), len)
        }
    }

    #[inline]
    pub fn increase_payload_size(&mut self, increase_by: usize) -> usize {
        unsafe { (*self.mbuf).add_data_end(increase_by) }
    }

    #[inline]
    pub fn trim_payload_size(&mut self, trim_by: usize) -> usize {
        unsafe { (*self.mbuf).remove_data_end(trim_by) }
    }

    #[inline]
    pub fn copy_payload(&mut self, other: &Self) -> usize {
        let copy_len = other.payload_size();
        let dst = self.payload();
        let src = other.payload();

        let payload_size = self.payload_size();

        let should_copy = if payload_size < copy_len {
            let increment = copy_len - payload_size;
            self.increase_payload_size(increment)
        } else {
            copy_len
        };

        unsafe {
            ptr::copy_nonoverlapping(src, dst, should_copy);
            should_copy
        }
    }

    #[inline]
    pub fn refcnt(&self) -> u16 {
        unsafe { (*self.mbuf).refcnt() }
    }

    /// Get the mbuf reference by this packet.
    ///
    /// # Safety
    /// The reference held by this Packet is nulled out as a result of this code. The callee is responsible for
    /// appropriately freeing this mbuf from here-on out.
    #[inline]
    pub unsafe fn get_mbuf(&mut self) -> *mut MBuf {
        let mbuf = self.mbuf;
        self.mbuf = ptr::null_mut();
        mbuf
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;
extern crate clap;
#[macro_use] extern crate version;
#[macro_use] extern crate log;
extern crate walkdir;

extern crate libimagrt;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;
use clap::{Arg, App, AppSettings, SubCommand};

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .and_then(|s| s.splitn(2, "-").nth(1).map(String::from))
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    get_commands()
        .iter()
        .fold(app, |app, cmd| app.subcommand(SubCommand::with_name(cmd)))
        .arg(Arg::with_name("version")
             .long("version")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the version of imag"))
        .arg(Arg::with_name("versions")
             .long("versions")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the versions of the imag commands"))
        .arg(Arg::with_name("help")
             .long("help")
             .short("h")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Show help"))
        .subcommand(SubCommand::with_name("help").help("Show help"))
        .settings(&[AppSettings::AllowExternalSubcommands])
}

fn main() {
    let appname  = "imag";
    let version  = &version!();
    let about    = "imag - the PIM suite for the commandline";
    let rt       = generate_runtime_setup(appname, version, about, build_ui);
    let matches  = rt.cli();

    debug!("matches: {:?}", matches);
    if matches.is_present("help") {
        debug!("Calling help()");
        help(get_commands());
        exit(0);
    }

    if matches.is_present("version") {
        debug!("Showing version");
        println!("imag {}", &version!()[..]);
        exit(0);
    }

    if matches.is_present("versions") {
        debug!("Showing versions");
        let mut result = vec![];
        for command in get_commands().iter() {
            result.push(crossbeam::scope(|scope| {
                scope.spawn(|| {
                    let v = Command::new(command).arg("--version").output();
                    match v {
                        Ok(v) => match String::from_utf8(v.stdout) {
                            Ok(s) => format!("{} -> {}", command, s),
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        },
                        Err(e) => format!("Failed calling {} -> {:?}", command, e),
                    }
                })
            }))
        }

        for versionstring in result.into_iter().map(|handle| handle.join()) {
            println!("{}", versionstring);
        }
    }

    matches.subcommand_name()
        .map(|subcommand| {

            let mut subcommand_args = vec![];

            for arg in Runtime::arg_names() {
                matches.value_of(arg)
                    .map(|value| {
                        subcommand_args.push(arg);
                        subcommand_args.push(value);
                    });
            }

            debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args);

            match Command::new(format!("imag-{}", subcommand))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status);
                        println!("{} exited with non-zero exit code", subcommand);
                        exit(exit_status.code().unwrap_or(42));
                    }
                    debug!("Successful exit!");
                },

                Err(e) => {
                    debug!("Error calling the subcommand");
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", subcommand);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", subcommand);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }
        });
}
<commit_msg>Change build_ui to use subcommands()<commit_after>extern crate crossbeam;
extern crate clap;
#[macro_use] extern crate version;
#[macro_use] extern crate log;
extern crate walkdir;

extern crate libimagrt;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;
use clap::{Arg, App, AppSettings, SubCommand};

use libimagrt::runtime::Runtime;
use libimagrt::setup::generate_runtime_setup;

fn help(cmds: Vec<String>) {
    println!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:
    "#);

    for cmd in cmds.iter() {
        println!("\t{}", cmd);
    }

    println!(r#"

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#);
}

fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .and_then(|s| s.splitn(2, "-").nth(1).map(String::from))
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
    app
        .settings(&[AppSettings::AllowExternalSubcommands])
        .arg(Arg::with_name("version")
             .long("version")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the version of imag"))
        .arg(Arg::with_name("versions")
             .long("versions")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the versions of the imag commands"))
        .arg(Arg::with_name("help")
             .long("help")
             .short("h")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Show help"))
        .subcommand(SubCommand::with_name("help").help("Show help"))
        .subcommands(get_commands()
            .iter()
            .map(|cmd| SubCommand::with_name(cmd))
        )
}

fn main() {
    let appname  = "imag";
    let version  = &version!();
    let about    = "imag - the PIM suite for the commandline";
    let rt       = generate_runtime_setup(appname, version, about, build_ui);
    let matches  = rt.cli();

    debug!("matches: {:?}", matches);
    if matches.is_present("help") {
        debug!("Calling help()");
        help(get_commands());
        exit(0);
    }

    if matches.is_present("version") {
        debug!("Showing version");
        println!("imag {}", &version!()[..]);
        exit(0);
    }

    if matches.is_present("versions") {
        debug!("Showing versions");
        let mut result = vec![];
        for command in get_commands().iter() {
            result.push(crossbeam::scope(|scope| {
                scope.spawn(|| {
                    let v = Command::new(command).arg("--version").output();
                    match v {
                        Ok(v) => match String::from_utf8(v.stdout) {
                            Ok(s) => format!("{} -> {}", command, s),
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        },
                        Err(e) => format!("Failed calling {} -> {:?}", command, e),
                    }
                })
            }))
        }

        for versionstring in result.into_iter().map(|handle| handle.join()) {
            println!("{}", versionstring);
        }
    }

    match matches.subcommand() {
        (subcommand, Some(scmd)) => {
            let subcommand_args : Vec<&str> = scmd.values_of(subcommand).unwrap().collect();
            debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args);

            match Command::new(format!("imag-{}", subcommand))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status);
                        println!("{} exited with non-zero exit code", subcommand);
                        exit(exit_status.code().unwrap_or(42));
                    }
                    debug!("Successful exit!");
                },

                Err(e) => {
                    debug!("Error calling the subcommand");
                    match e.kind() {
                        ErrorKind::NotFound => {
                            println!("No such command: 'imag-{}'", subcommand);
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", subcommand);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1337);
                        }
                    }
                }
            }
        },
        // clap ensures we have valid input by exiting if not.
        // The above case is a catch-all for subcommands,
        // so nothing else needs to be expexted.
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>//! This module implements run-time feature detection.
//!
//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a
//! feature as a string-literal, and return a boolean indicating whether the
//! feature is enabled at run-time or not.
//!
//! These macros do two things:
//! * map the string-literal into an integer stored as a `Feature` enum,
//! * call a `os::check_for(x: Feature)` function that returns `true` if the
//! feature is enabled.
//!
//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs`
//! modules.
//!
//! The `check_for` functions are, in general, Operating System dependent. Most
//! architectures do not allow user-space programs to query the feature bits
//! due to security concerns (x86 is the big exception). These functions are
//! implemented in the `os/{target_os}.rs` modules.

use cfg_if::cfg_if;

#[macro_use]
mod error_macros;

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        #[path = "arch/x86.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "arm")] {
        #[path = "arch/arm.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "aarch64")] {
        #[path = "arch/aarch64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
        #[path = "arch/riscv.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc")] {
        #[path = "arch/powerpc.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc64")] {
        #[path = "arch/powerpc64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips")] {
        #[path = "arch/mips.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips64")] {
        #[path = "arch/mips64.rs"]
        #[macro_use]
        mod arch;
    } else {
        // Unimplemented architecture:
        #[allow(dead_code)]
        mod arch {
            #[doc(hidden)]
            pub(crate) enum Feature {
                Null
            }
            #[doc(hidden)]
            pub mod __is_feature_detected {}

            impl Feature {
                #[doc(hidden)]
                pub(crate) fn from_str(_s: &str) -> Result<Feature, ()> { Err(()) }
                #[doc(hidden)]
                pub(crate) fn to_str(self) -> &'static str { "" }
            }
        }
    }
}

// This module needs to be public because the `is_{arch}_feature_detected!`
// macros expand calls to items within it in user crates.
#[doc(hidden)]
pub use self::arch::__is_feature_detected;

pub(crate) use self::arch::Feature;

mod bit;
mod cache;

cfg_if! {
    if #[cfg(miri)] {
        // When running under miri all target-features that are not enabled at
        // compile-time are reported as disabled at run-time.
        //
        // For features for which `cfg(target_feature)` returns true,
        // this run-time detection logic is never called.
        #[path = "os/other.rs"]
        mod os;
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        // On x86/x86_64 no OS specific functionality is required.
        #[path = "os/x86.rs"]
        mod os;
    } else if #[cfg(all(target_os = "linux", feature = "libc"))] {
        #[path = "os/linux/mod.rs"]
        mod os;
    } else if #[cfg(all(target_os = "freebsd", feature = "libc"))] {
        #[cfg(target_arch = "aarch64")]
        #[path = "os/aarch64.rs"]
        mod aarch64;
        #[path = "os/freebsd/mod.rs"]
        mod os;
    } else if #[cfg(all(target_os = "windows", target_arch = "aarch64"))] {
        #[path = "os/windows/aarch64.rs"]
        mod os;
    } else {
        #[path = "os/other.rs"]
        mod os;
    }
}

/// Performs run-time feature detection.
#[inline]
#[allow(dead_code)]
fn check_for(x: Feature) -> bool {
    cache::test(x as u32)
}

/// Returns an `Iterator<Item=(&'static str, bool)>` where
/// `Item.0` is the feature name, and `Item.1` is a `bool` which
/// is `true` if the feature is supported by the host and `false` otherwise.
#[unstable(feature = "stdsimd", issue = "27731")]
pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
    cfg_if! {
        if #[cfg(any(
            target_arch = "x86",
            target_arch = "x86_64",
            target_arch = "arm",
            target_arch = "aarch64",
            target_arch = "riscv32",
            target_arch = "riscv64",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "mips",
            target_arch = "mips64",
        ))] {
            (0_u8..Feature::_last as u8).map(|discriminant: u8| {
                #[allow(bindings_with_variant_name)] // RISC-V has Feature::f
                let f: Feature = unsafe { core::mem::transmute(discriminant) };
                let name: &'static str = f.to_str();
                let enabled: bool = check_for(f);
                (name, enabled)
            })
        } else {
            None.into_iter()
        }
    }
}
<commit_msg>Emit the full is_{arch}_feature_detected! macro on all arches when building docs (#1276)<commit_after>//! This module implements run-time feature detection.
//!
//! The `is_{arch}_feature_detected!("feature-name")` macros take the name of a
//! feature as a string-literal, and return a boolean indicating whether the
//! feature is enabled at run-time or not.
//!
//! These macros do two things:
//! * map the string-literal into an integer stored as a `Feature` enum,
//! * call a `os::check_for(x: Feature)` function that returns `true` if the
//! feature is enabled.
//!
//! The `Feature` enums are also implemented in the `arch/{target_arch}.rs`
//! modules.
//!
//! The `check_for` functions are, in general, Operating System dependent. Most
//! architectures do not allow user-space programs to query the feature bits
//! due to security concerns (x86 is the big exception). These functions are
//! implemented in the `os/{target_os}.rs` modules.

use cfg_if::cfg_if;

#[cfg(not(doc))]
#[macro_use]
mod error_macros;

#[macro_use]
mod macros;

cfg_if! {
    if #[cfg(doc)] {
        // When building docs, emit the full macro for all supported arches.
        #[allow(dead_code)]
        mod arch {
            #[path = "x86.rs"]
            #[macro_use]
            mod x86;
            #[path = "arm.rs"]
            #[macro_use]
            mod arm;
            #[path = "aarch64.rs"]
            #[macro_use]
            mod aarch64;
            #[path = "riscv.rs"]
            #[macro_use]
            mod riscv;
            #[path = "powerpc.rs"]
            #[macro_use]
            mod powerpc;
            #[path = "powerpc64.rs"]
            #[macro_use]
            mod powerpc64;
            #[path = "mips.rs"]
            #[macro_use]
            mod mips;
            #[path = "mips64.rs"]
            #[macro_use]
            mod mips64;

            #[doc(hidden)]
            pub(crate) enum Feature {
                Null
            }
            #[doc(hidden)]
            pub mod __is_feature_detected {}

            impl Feature {
                #[doc(hidden)]
                pub(crate) fn from_str(_s: &str) -> Result<Feature, ()> { Err(()) }
                #[doc(hidden)]
                pub(crate) fn to_str(self) -> &'static str { "" }
            }
        }
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        #[path = "arch/x86.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "arm")] {
        #[path = "arch/arm.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "aarch64")] {
        #[path = "arch/aarch64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
        #[path = "arch/riscv.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc")] {
        #[path = "arch/powerpc.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "powerpc64")] {
        #[path = "arch/powerpc64.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips")] {
        #[path = "arch/mips.rs"]
        #[macro_use]
        mod arch;
    } else if #[cfg(target_arch = "mips64")] {
        #[path = "arch/mips64.rs"]
        #[macro_use]
        mod arch;
    } else {
        // Unimplemented architecture:
        #[allow(dead_code)]
        mod arch {
            #[doc(hidden)]
            pub(crate) enum Feature {
                Null
            }
            #[doc(hidden)]
            pub mod __is_feature_detected {}

            impl Feature {
                #[doc(hidden)]
                pub(crate) fn from_str(_s: &str) -> Result<Feature, ()> { Err(()) }
                #[doc(hidden)]
                pub(crate) fn to_str(self) -> &'static str { "" }
            }
        }
    }
}

// This module needs to be public because the `is_{arch}_feature_detected!`
// macros expand calls to items within it in user crates.
#[doc(hidden)]
pub use self::arch::__is_feature_detected;

pub(crate) use self::arch::Feature;

mod bit;
mod cache;

cfg_if! {
    if #[cfg(miri)] {
        // When running under miri all target-features that are not enabled at
        // compile-time are reported as disabled at run-time.
        //
        // For features for which `cfg(target_feature)` returns true,
        // this run-time detection logic is never called.
        #[path = "os/other.rs"]
        mod os;
    } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
        // On x86/x86_64 no OS specific functionality is required.
        #[path = "os/x86.rs"]
        mod os;
    } else if #[cfg(all(target_os = "linux", feature = "libc"))] {
        #[path = "os/linux/mod.rs"]
        mod os;
    } else if #[cfg(all(target_os = "freebsd", feature = "libc"))] {
        #[cfg(target_arch = "aarch64")]
        #[path = "os/aarch64.rs"]
        mod aarch64;
        #[path = "os/freebsd/mod.rs"]
        mod os;
    } else if #[cfg(all(target_os = "windows", target_arch = "aarch64"))] {
        #[path = "os/windows/aarch64.rs"]
        mod os;
    } else {
        #[path = "os/other.rs"]
        mod os;
    }
}

/// Performs run-time feature detection.
#[inline]
#[allow(dead_code)]
fn check_for(x: Feature) -> bool {
    cache::test(x as u32)
}

/// Returns an `Iterator<Item=(&'static str, bool)>` where
/// `Item.0` is the feature name, and `Item.1` is a `bool` which
/// is `true` if the feature is supported by the host and `false` otherwise.
#[unstable(feature = "stdsimd", issue = "27731")]
pub fn features() -> impl Iterator<Item = (&'static str, bool)> {
    cfg_if! {
        if #[cfg(any(
            target_arch = "x86",
            target_arch = "x86_64",
            target_arch = "arm",
            target_arch = "aarch64",
            target_arch = "riscv32",
            target_arch = "riscv64",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "mips",
            target_arch = "mips64",
        ))] {
            (0_u8..Feature::_last as u8).map(|discriminant: u8| {
                #[allow(bindings_with_variant_name)] // RISC-V has Feature::f
                let f: Feature = unsafe { core::mem::transmute(discriminant) };
                let name: &'static str = f.to_str();
                let enabled: bool = check_for(f);
                (name, enabled)
            })
        } else {
            None.into_iter()
        }
    }
}
<|endoftext|>


<commit_before>use utils::RingBuffer;
use std::cmp::max;

/// Results from inserting into `ReorderedBuffer`
pub enum InsertionResult {
    /// Successfully inserted all the data (`written` should always be the same as the length of the input).
    Inserted { written: usize, available: usize },
    /// Inserted some of the data (recorded in `written`) but the buffer is out of space.
    OutOfMemory { written: usize, available: usize },
}

enum State {
    Closed,
    Connected,
    ConnectedOutOfOrder,
}

/// Structure to record unordered data.
#[derive(Default)]
struct Segment {
    pub prev: isize,
    pub begin: usize,
    pub length: usize,
    pub next: isize,
    pub idx: isize,
}

impl Segment {
    pub fn new(idx: isize, begin: usize, length: usize) -> Segment {
        Segment { idx: idx, prev: -1, next: -1,  begin: begin, length: length }
    }
}

/// A linked list of segments, this tries to avoid allocations whenever possible. In steady state (regardless of bad
/// choices made by the developer) there should be no allocations.
struct SegmentList {
    storage: Vec<Segment>,
    available: Vec<isize>,
    head: isize,
    tail: isize,
}

impl SegmentList {
    /// Create a segement list expecting that we will need no more than `length` segments.
    pub fn new(length: usize) -> SegmentList {
        SegmentList {
            storage: (0..(length as isize)).map(|i| Segment::new(i, 0, 0)).collect(),
            available: (0..(length as isize)).collect(),
            head: -1,
            tail: -1,
        }
    }

    /// Remove a node.
    fn remove_node(&mut self, node: isize) {
        self.storage[node as usize].length = 0;
        self.available.push(node);
    }

    /// Find an empty node that we can insert into the list.
    #[inline]
    fn find_available_node(&mut self) -> isize {
        if let Some(nidx) = self.available.pop() {
            nidx
        } else {
            let idx = self.storage.len() as isize;
            self.storage.push(Segment::new(idx, 0, 0));
            idx
        }
    }

    /// Insert a node before `next`.
    #[inline]
    fn insert_before_node(&mut self, next: isize, begin: usize, len: usize) -> isize {
        let idx = self.find_available_node();
        self.storage[idx as usize].begin = begin;
        self.storage[idx as usize].length = len;
        self.storage[idx as usize].next = next;
        if next != -1 {
            let prev = self.storage[next as usize].prev;
            self.storage[idx as usize].prev = prev;
            self.storage[next as usize].prev = idx;
            if prev != -1 {
                self.storage[prev as usize].next = idx;
            }
        } else {
            self.storage[idx as usize].prev = -1;
        }
        idx
    }

    /// Insert a node at the tail of the list.
    #[inline]
    fn insert_at_tail(&mut self, begin: usize, len: usize) -> isize {
        let idx = self.find_available_node();
        let idx_u = idx as usize;
        self.storage[idx_u].begin = begin;
        self.storage[idx_u].length = len;
        self.storage[idx_u].next = -1;
        self.storage[idx_u].prev = self.tail;
        self.storage[self.tail as usize].next = idx;
        self.tail = idx;
        idx
    }

    /// Insert a segment.
    #[inline]
    pub fn insert_segment(&mut self, begin: usize, len: usize) -> Option<isize> {
        let mut idx = self.head;
        if idx == -1 { // Special case the first insertion.
            idx = self.insert_before_node(-1, begin, len);
            self.head = idx;
            self.tail = idx;
            Some(idx)
        } else {
            let end = begin + len;
            while idx != -1 {
                let segment_end = self.storage[idx as usize].begin + self.storage[idx as usize].length;
                if segment_end == begin { // We can just add to the current segment.
                    self.storage[idx as usize].length += len;
                    break;
                } else if self.storage[idx as usize].begin >= end { // We are on to segments that are further down, insert
                    idx = self.insert_before_node(idx, begin, len);
                    break;
                } else if self.storage[idx as usize].begin <= begin { // Overlapping segment
                    let new_end = max(segment_end, end);
                    self.storage[idx as usize].length = new_end - self.storage[idx as usize].begin;
                    break;
                } else {
                    idx = self.storage[idx as usize].next;
                }
            }

            if idx == -1 {
                // Nothing matched, so let us insert at the tail.
                idx = self.insert_at_tail(begin, len);
                Some(idx)
            } else {
                // Check if we should/can merge. This only checks subsequent segments (since the prior ones should
                // already have been checked).
                let mut next = self.storage[idx as usize].next;
                while next != -1 {
                    let end = self.storage[idx as usize].begin + self.storage[idx as usize].length;
                    if  end <= self.storage[next as usize].begin {
                        // We should merge.
                        // Figure out how much of the next segment is non-overlapping
                        let merge_len = (end - self.storage[next as usize].begin) + self.storage[next as usize].length;
                        let to_free = next;
                        // Fix up pointers and length
                        self.storage[idx as usize].length += merge_len;
                        next = self.storage[to_free as usize].next;
                        self.storage[idx as usize].next = next;
                        self.storage[next as usize].prev = idx;
                        // Free the node
                        self.remove_node(to_free);

                    }
                }
                Some(idx)
            }
        }
    }

    /// Is `seg` the head of the list.
    pub fn is_head(&self, seg: isize) -> bool {
        self.head == seg
    }

    /// Remove the head of the list.
    #[inline]
    fn remove_head(&mut self) {
        let head = self.head;
        self.head = self.storage[head as usize].next;
        self.remove_node(head);
    }

    /// Consume some amount of data from the beginning.
    pub fn consume_head_data(&mut self, seq: usize, consumed: usize) -> bool {
        let idx = self.head as usize;
        // This is just an integrity check.
        if self.storage[idx].begin != seq {
            false
        } else {
            // Note we do not need to look beyond the head since we always merge segments.
            self.storage[idx].begin += consumed;
            self.storage[idx].length -= consumed;
            if self.storage[idx].length == 0 {
                self.remove_head();
            }
            true
        }
    }

    /// Clear the list.
    pub fn clear(&mut self) {
        let mut idx = self.head;
        while idx != -1 {
            let next = self.storage[idx as usize].next;
            self.remove_node(idx);
            idx = next;
        }
        self.head = -1;
        self.tail = -1;
    }

    /// Get a particular segment.
    #[inline]
    pub fn get_segment<'a>(&'a self, idx: isize) -> &'a Segment {
        &self.storage[idx as usize]
    }

    #[inline]
    pub fn empty(&self) -> bool {
        self.head == -1
    }
}

/// A structure for storing data that might be received out of order. This allows data to be inserted in any order, but
/// then allows ordered read from data.
pub struct ReorderedBuffer {
    data: RingBuffer,
    segment_list: SegmentList,
    buffer_size: usize,
    state: State,
    head_seq: usize,
    tail_seq: usize,
}

const PAGE_SIZE: usize = 4096; // Page size in bytes, not using huge pages here.

impl ReorderedBuffer {
    // This is pub for testing, probably just move it out to utils
    #[inline]
    pub fn round_to_pages(buffer_size: usize) -> usize {
        (buffer_size + (PAGE_SIZE - 1)) & !(PAGE_SIZE - 1)
    }

    // This is pub for testing, probably just move it out to utils
    #[inline]
    pub fn round_to_power_of_2(mut size: usize) -> usize {
        size = size.wrapping_sub(1);
        size |= size >> 1;
        size |= size >> 2;
        size |= size >> 4;
        size |= size >> 8;
        size |= size >> 16;
        size |= size >> 32;
        size = size.wrapping_add(1);
        size
    }

    #[inline]
    pub fn buffer_size(&self) -> usize {
        self.buffer_size
    }

    #[inline]
    pub fn available(&self) -> usize {
        self.data.available()
    }

    pub fn new(buffer_size: usize) -> ReorderedBuffer {
        ReorderedBuffer::new_with_segments(buffer_size, buffer_size / 64)
    }

    pub fn new_with_segments(buffer_size: usize, segment_size: usize) -> ReorderedBuffer {
        let page_aligned_size = ReorderedBuffer::round_to_pages(buffer_size);
        let pages = ReorderedBuffer::round_to_power_of_2(page_aligned_size / PAGE_SIZE);
        ReorderedBuffer {
            data: RingBuffer::new(pages).unwrap(),
            buffer_size: page_aligned_size,
            state: State::Closed,
            head_seq: 0,
            tail_seq: 0,
            segment_list: SegmentList::new(segment_size), // Assuming we don't receive small chunks.
        }
    }

    pub fn reset(&mut self) {
        self.state = State::Closed;
        self.segment_list.clear();
        self.data.clear();
    }

    fn fast_path_insert(&mut self, data: &[u8]) -> InsertionResult {
        let written = self.data.write_at_tail(data);
        self.tail_seq += written;
        if written == data.len() {
            InsertionResult::Inserted { written: written, available: self.available() }
        } else {
            InsertionResult::OutOfMemory { written: written, available: self.available() }
        }
    }

    fn slow_path_insert(&mut self, seq: usize, data: &[u8]) -> InsertionResult {
        let end = seq + data.len();

        if self.tail_seq > seq && end > self.tail_seq { // Some of the data overlaps with stuff we have received before.
            let begin = self.tail_seq - seq;
            self.fast_path_insert(&data[begin..])
        } else if end < self.tail_seq { // All the data overlaps.
            InsertionResult::Inserted { written: data.len(), available: self.available() }
        } else { // We are about to insert out of order data.
            // Change state to indicate we have out of order data; this means we need to do additional processing when
            // receiving data.
            self.state = State::ConnectedOutOfOrder;
            // Insert current in-order data into the segment list.
            self.segment_list.insert_segment(self.head_seq, self.data.available());
            // Call out-of-order insertion.
            self.out_of_order_insert(seq, data)
        }
    }

    fn out_of_order_insert(&mut self, seq: usize, data: &[u8]) -> InsertionResult {
        // FIXME: Transition back to Connected
        if self.tail_seq == seq { // Writing at tail
            // Write some data
            let mut written = self.data.write_at_tail(data);
            // Advance tail_seq based on written data (since write_at_tail already did that).
            self.tail_seq += written;
            {
                // Insert into segment list.
                let segment = self.segment_list.insert_segment(seq, written).unwrap();
                // Since we are writing to the beginning, this must always be the head.
                assert!(self.segment_list.is_head(segment));
                // Compute the end of the segment, this might in fact be larger than size
                let seg = self.segment_list.get_segment(segment);
                let seg_end = seg.begin + seg.length;
                // Integrity test.
                assert!(seg_end >= self.tail_seq);
                // We need to know the increment.
                let incr = seg_end - self.tail_seq;

                // If we have overlapped into data we received before, just drop the overlapping data.
                if written < incr {
                    written = incr;
                }
                self.tail_seq = seg_end; // Advance tail_seq
                self.data.seek_tail(incr); // Increment tail for the ring buffer.
            }
            InsertionResult::Inserted { written: written, available: self.available() }
        } else if self.tail_seq >= seq {
            let offset = self.tail_seq - seq;
            let remaining = data.len() - offset;
            if remaining > 0 {
                let tail_seq = self.tail_seq;
                self.out_of_order_insert(tail_seq, &data[offset..])
            } else {
                InsertionResult::Inserted { written: data.len(), available: self.available() }
            }
        } else { // self.tail_seq < seq
            // Compute offset from tail where this should be written
            let offset = seq - self.tail_seq;
            // Write stuff
            let written = self.data.write_at_offset_from_tail(offset, data);
            // Insert segment at the right place
            self.segment_list.insert_segment(seq, written);
            if written == data.len() {
                InsertionResult::Inserted { written: written, available: self.available() }
            } else {
                InsertionResult::OutOfMemory { written: written, available: self.available() }
            }
        }
    }

    pub fn seq(&mut self, seq: usize, data: &[u8]) -> InsertionResult {
        self.state = State::Connected;
        self.head_seq = seq;
        self.tail_seq = seq;
        self.fast_path_insert(data)
    }

    pub fn add_data(&mut self, seq: usize, data: &[u8]) -> InsertionResult {
        match self.state {
            State::Connected => {
                if seq == self.tail_seq { // Fast path
                    self.fast_path_insert(data)
                } else { // Slow path
                    self.slow_path_insert(seq, data)
                }
            },
            State::ConnectedOutOfOrder => {
                self.out_of_order_insert(seq, data)
            },
            State::Closed => {
                panic!("Unexpected data");
            }
        }
    }

    #[inline]
    fn read_data_common(&mut self, mut data: &mut [u8]) -> usize {
        let read = self.data.read_from_head(data);
        self.head_seq = self.head_seq.wrapping_add(read);
        read
    }

    /// Read data from the buffer. The amount of data read is limited by the amount of in-order-data available at the
    /// moment.
    pub fn read_data(&mut self, mut data: &mut [u8]) -> usize {
        match self.state {
            State::Connected => self.read_data_common(data),
            State::ConnectedOutOfOrder => {
                let seq = self.head_seq;
                let read = self.read_data_common(data);
                // Record this in the segment list.
                self.segment_list.consume_head_data(seq, read);
                read
            },
            State::Closed => 0
        }
    }
}
<commit_msg>Return to fast path when possible<commit_after>use utils::RingBuffer;
use std::cmp::max;

/// Results from inserting into `ReorderedBuffer`
pub enum InsertionResult {
    /// Successfully inserted all the data (`written` should always be the same as the length of the input).
    Inserted { written: usize, available: usize },
    /// Inserted some of the data (recorded in `written`) but the buffer is out of space.
    OutOfMemory { written: usize, available: usize },
}

enum State {
    Closed,
    Connected,
    ConnectedOutOfOrder,
}

/// Structure to record unordered data.
#[derive(Default)]
struct Segment {
    pub prev: isize,
    pub begin: usize,
    pub length: usize,
    pub next: isize,
    pub idx: isize,
}

impl Segment {
    pub fn new(idx: isize, begin: usize, length: usize) -> Segment {
        Segment { idx: idx, prev: -1, next: -1,  begin: begin, length: length }
    }
}

/// A linked list of segments, this tries to avoid allocations whenever possible. In steady state (regardless of bad
/// choices made by the developer) there should be no allocations.
struct SegmentList {
    storage: Vec<Segment>,
    available: Vec<isize>,
    head: isize,
    tail: isize,
}

impl SegmentList {
    /// Create a segement list expecting that we will need no more than `length` segments.
    pub fn new(length: usize) -> SegmentList {
        SegmentList {
            storage: (0..(length as isize)).map(|i| Segment::new(i, 0, 0)).collect(),
            available: (0..(length as isize)).collect(),
            head: -1,
            tail: -1,
        }
    }

    /// Remove a node.
    fn remove_node(&mut self, node: isize) {
        self.storage[node as usize].length = 0;
        self.available.push(node);
    }

    /// Find an empty node that we can insert into the list.
    #[inline]
    fn find_available_node(&mut self) -> isize {
        if let Some(nidx) = self.available.pop() {
            nidx
        } else {
            let idx = self.storage.len() as isize;
            self.storage.push(Segment::new(idx, 0, 0));
            idx
        }
    }

    /// Insert a node before `next`.
    #[inline]
    fn insert_before_node(&mut self, next: isize, begin: usize, len: usize) -> isize {
        let idx = self.find_available_node();
        self.storage[idx as usize].begin = begin;
        self.storage[idx as usize].length = len;
        self.storage[idx as usize].next = next;
        if next != -1 {
            let prev = self.storage[next as usize].prev;
            self.storage[idx as usize].prev = prev;
            self.storage[next as usize].prev = idx;
            if prev != -1 {
                self.storage[prev as usize].next = idx;
            }
        } else {
            self.storage[idx as usize].prev = -1;
        }
        idx
    }

    /// Insert a node at the tail of the list.
    #[inline]
    fn insert_at_tail(&mut self, begin: usize, len: usize) -> isize {
        let idx = self.find_available_node();
        let idx_u = idx as usize;
        self.storage[idx_u].begin = begin;
        self.storage[idx_u].length = len;
        self.storage[idx_u].next = -1;
        self.storage[idx_u].prev = self.tail;
        self.storage[self.tail as usize].next = idx;
        self.tail = idx;
        idx
    }

    /// Insert a segment.
    #[inline]
    pub fn insert_segment(&mut self, begin: usize, len: usize) -> Option<isize> {
        let mut idx = self.head;
        if idx == -1 { // Special case the first insertion.
            idx = self.insert_before_node(-1, begin, len);
            self.head = idx;
            self.tail = idx;
            Some(idx)
        } else {
            let end = begin + len;
            while idx != -1 {
                let segment_end = self.storage[idx as usize].begin + self.storage[idx as usize].length;
                if segment_end == begin { // We can just add to the current segment.
                    self.storage[idx as usize].length += len;
                    break;
                } else if self.storage[idx as usize].begin >= end { // We are on to segments that are further down, insert
                    idx = self.insert_before_node(idx, begin, len);
                    break;
                } else if self.storage[idx as usize].begin <= begin { // Overlapping segment
                    let new_end = max(segment_end, end);
                    self.storage[idx as usize].length = new_end - self.storage[idx as usize].begin;
                    break;
                } else {
                    idx = self.storage[idx as usize].next;
                }
            }

            if idx == -1 {
                // Nothing matched, so let us insert at the tail.
                idx = self.insert_at_tail(begin, len);
                Some(idx)
            } else {
                // Check if we should/can merge. This only checks subsequent segments (since the prior ones should
                // already have been checked).
                let mut next = self.storage[idx as usize].next;
                while next != -1 {
                    let end = self.storage[idx as usize].begin + self.storage[idx as usize].length;
                    if  end <= self.storage[next as usize].begin {
                        // We should merge.
                        // Figure out how much of the next segment is non-overlapping
                        let merge_len = (end - self.storage[next as usize].begin) + self.storage[next as usize].length;
                        let to_free = next;
                        // Fix up pointers and length
                        self.storage[idx as usize].length += merge_len;
                        next = self.storage[to_free as usize].next;
                        self.storage[idx as usize].next = next;
                        self.storage[next as usize].prev = idx;
                        // Free the node
                        self.remove_node(to_free);

                    }
                }
                Some(idx)
            }
        }
    }

    /// Is `seg` the head of the list.
    pub fn is_head(&self, seg: isize) -> bool {
        self.head == seg
    }

    /// Remove the head of the list.
    #[inline]
    fn remove_head(&mut self) {
        let head = self.head;
        self.head = self.storage[head as usize].next;
        self.remove_node(head);
    }

    /// Consume some amount of data from the beginning.
    pub fn consume_head_data(&mut self, seq: usize, consumed: usize) -> bool {
        let idx = self.head as usize;
        // This is just an integrity check.
        if self.storage[idx].begin != seq {
            false
        } else {
            // Note we do not need to look beyond the head since we always merge segments.
            self.storage[idx].begin += consumed;
            self.storage[idx].length -= consumed;
            if self.storage[idx].length == 0 {
                self.remove_head();
            }
            true
        }
    }

    /// Clear the list.
    pub fn clear(&mut self) {
        let mut idx = self.head;
        while idx != -1 {
            let next = self.storage[idx as usize].next;
            self.remove_node(idx);
            idx = next;
        }
        self.head = -1;
        self.tail = -1;
    }

    /// Get a particular segment.
    #[inline]
    pub fn get_segment<'a>(&'a self, idx: isize) -> &'a Segment {
        &self.storage[idx as usize]
    }

    #[inline]
    pub fn one_segment(&self) -> bool {
        self.head == -1 || self.storage[self.head as usize].next == -1
    }
}

/// A structure for storing data that might be received out of order. This allows data to be inserted in any order, but
/// then allows ordered read from data.
pub struct ReorderedBuffer {
    data: RingBuffer,
    segment_list: SegmentList,
    buffer_size: usize,
    state: State,
    head_seq: usize,
    tail_seq: usize,
}

const PAGE_SIZE: usize = 4096; // Page size in bytes, not using huge pages here.

impl ReorderedBuffer {
    // This is pub for testing, probably just move it out to utils
    #[inline]
    pub fn round_to_pages(buffer_size: usize) -> usize {
        (buffer_size + (PAGE_SIZE - 1)) & !(PAGE_SIZE - 1)
    }

    // This is pub for testing, probably just move it out to utils
    #[inline]
    pub fn round_to_power_of_2(mut size: usize) -> usize {
        size = size.wrapping_sub(1);
        size |= size >> 1;
        size |= size >> 2;
        size |= size >> 4;
        size |= size >> 8;
        size |= size >> 16;
        size |= size >> 32;
        size = size.wrapping_add(1);
        size
    }

    #[inline]
    pub fn buffer_size(&self) -> usize {
        self.buffer_size
    }

    #[inline]
    pub fn available(&self) -> usize {
        self.data.available()
    }

    pub fn new(buffer_size: usize) -> ReorderedBuffer {
        ReorderedBuffer::new_with_segments(buffer_size, buffer_size / 64)
    }

    pub fn new_with_segments(buffer_size: usize, segment_size: usize) -> ReorderedBuffer {
        let page_aligned_size = ReorderedBuffer::round_to_pages(buffer_size);
        let pages = ReorderedBuffer::round_to_power_of_2(page_aligned_size / PAGE_SIZE);
        ReorderedBuffer {
            data: RingBuffer::new(pages).unwrap(),
            buffer_size: page_aligned_size,
            state: State::Closed,
            head_seq: 0,
            tail_seq: 0,
            segment_list: SegmentList::new(segment_size), // Assuming we don't receive small chunks.
        }
    }

    pub fn reset(&mut self) {
        self.state = State::Closed;
        self.segment_list.clear();
        self.data.clear();
    }

    fn fast_path_insert(&mut self, data: &[u8]) -> InsertionResult {
        let written = self.data.write_at_tail(data);
        self.tail_seq += written;
        if written == data.len() {
            InsertionResult::Inserted { written: written, available: self.available() }
        } else {
            InsertionResult::OutOfMemory { written: written, available: self.available() }
        }
    }

    fn slow_path_insert(&mut self, seq: usize, data: &[u8]) -> InsertionResult {
        let end = seq + data.len();

        if self.tail_seq > seq && end > self.tail_seq { // Some of the data overlaps with stuff we have received before.
            let begin = self.tail_seq - seq;
            self.fast_path_insert(&data[begin..])
        } else if end < self.tail_seq { // All the data overlaps.
            InsertionResult::Inserted { written: data.len(), available: self.available() }
        } else { // We are about to insert out of order data.
            // Change state to indicate we have out of order data; this means we need to do additional processing when
            // receiving data.
            self.state = State::ConnectedOutOfOrder;
            // Insert current in-order data into the segment list.
            self.segment_list.insert_segment(self.head_seq, self.data.available());
            // Call out-of-order insertion.
            self.out_of_order_insert(seq, data)
        }
    }

    fn out_of_order_insert(&mut self, seq: usize, data: &[u8]) -> InsertionResult {
        // FIXME: Transition back to Connected
        if self.tail_seq == seq { // Writing at tail
            // Write some data
            let mut written = self.data.write_at_tail(data);
            // Advance tail_seq based on written data (since write_at_tail already did that).
            self.tail_seq += written;
            {
                // Insert into segment list.
                let segment = self.segment_list.insert_segment(seq, written).unwrap();
                // Since we are writing to the beginning, this must always be the head.
                assert!(self.segment_list.is_head(segment));
                // Compute the end of the segment, this might in fact be larger than size
                let seg = self.segment_list.get_segment(segment);
                let seg_end = seg.begin + seg.length;
                // Integrity test.
                assert!(seg_end >= self.tail_seq);
                // We need to know the increment.
                let incr = seg_end - self.tail_seq;

                // If we have overlapped into data we received before, just drop the overlapping data.
                if written < incr {
                    written = incr;
                }
                self.tail_seq = seg_end; // Advance tail_seq
                self.data.seek_tail(incr); // Increment tail for the ring buffer.

            }
            if self.segment_list.one_segment() { // We only have one segment left, so now is a good time to switch
                                                 // back to fast path.
                self.segment_list.clear();
                self.state = State::Connected;
            }
            InsertionResult::Inserted { written: written, available: self.available() }
        } else if self.tail_seq >= seq {
            let offset = self.tail_seq - seq;
            let remaining = data.len() - offset;
            if remaining > 0 {
                let tail_seq = self.tail_seq;
                self.out_of_order_insert(tail_seq, &data[offset..])
            } else {
                InsertionResult::Inserted { written: data.len(), available: self.available() }
            }
        } else { // self.tail_seq < seq
            // Compute offset from tail where this should be written
            let offset = seq - self.tail_seq;
            // Write stuff
            let written = self.data.write_at_offset_from_tail(offset, data);
            // Insert segment at the right place
            self.segment_list.insert_segment(seq, written);
            if written == data.len() {
                InsertionResult::Inserted { written: written, available: self.available() }
            } else {
                InsertionResult::OutOfMemory { written: written, available: self.available() }
            }
        }
    }

    pub fn seq(&mut self, seq: usize, data: &[u8]) -> InsertionResult {
        self.state = State::Connected;
        self.head_seq = seq;
        self.tail_seq = seq;
        self.fast_path_insert(data)
    }

    pub fn add_data(&mut self, seq: usize, data: &[u8]) -> InsertionResult {
        match self.state {
            State::Connected => {
                if seq == self.tail_seq { // Fast path
                    self.fast_path_insert(data)
                } else { // Slow path
                    self.slow_path_insert(seq, data)
                }
            },
            State::ConnectedOutOfOrder => {
                self.out_of_order_insert(seq, data)
            },
            State::Closed => {
                panic!("Unexpected data");
            }
        }
    }

    #[inline]
    fn read_data_common(&mut self, mut data: &mut [u8]) -> usize {
        let read = self.data.read_from_head(data);
        self.head_seq = self.head_seq.wrapping_add(read);
        read
    }

    /// Read data from the buffer. The amount of data read is limited by the amount of in-order-data available at the
    /// moment.
    pub fn read_data(&mut self, mut data: &mut [u8]) -> usize {
        match self.state {
            State::Connected => self.read_data_common(data),
            State::ConnectedOutOfOrder => {
                let seq = self.head_seq;
                let read = self.read_data_common(data);
                // Record this in the segment list.
                self.segment_list.consume_head_data(seq, read);
                read
            },
            State::Closed => 0
        }
    }
}
<|endoftext|>


<commit_before>// edition:2018
#![warn(clippy::wrong_self_convention)]
#![warn(clippy::wrong_pub_self_convention)]
#![allow(dead_code)]

fn main() {}

mod issue6983 {
    pub struct Thing;
    pub trait Trait {
        fn to_thing(&self) -> Thing;
    }

    impl Trait for u8 {
        // don't trigger, e.g. `ToString` from `std` requires `&self`
        fn to_thing(&self) -> Thing {
            Thing
        }
    }

    trait ToU64 {
        fn to_u64(self) -> u64;
    }

    struct FooNoCopy;
    // don't trigger
    impl ToU64 for FooNoCopy {
        fn to_u64(self) -> u64 {
            2
        }
    }
}

mod issue7032 {
    trait Foo {
        fn from_usize(x: usize) -> Self;
    }
    // don't trigger
    impl Foo for usize {
        fn from_usize(x: usize) -> Self {
            x
        }
    }
}

mod issue7179 {
    pub struct S(i32);

    impl S {
        // don't trigger (`s` is not `self`)
        pub fn from_be(s: Self) -> Self {
            S(i32::from_be(s.0))
        }

        // lint
        pub fn from_be_self(self) -> Self {
            S(i32::from_be(self.0))
        }
    }

    trait T {
        // don't trigger (`s` is not `self`)
        fn from_be(s: Self) -> Self;
        // lint
        fn from_be_self(self) -> Self;
    }
}
<commit_msg>Auto merge of #7222 - ThibsG:WrongSelfTest, r=Manishearth<commit_after>// edition:2018
#![warn(clippy::wrong_self_convention)]
#![warn(clippy::wrong_pub_self_convention)]
#![allow(dead_code)]

fn main() {}

mod issue6983 {
    pub struct Thing;
    pub trait Trait {
        fn to_thing(&self) -> Thing;
    }

    impl Trait for u8 {
        // don't trigger, e.g. `ToString` from `std` requires `&self`
        fn to_thing(&self) -> Thing {
            Thing
        }
    }

    trait ToU64 {
        fn to_u64(self) -> u64;
    }

    struct FooNoCopy;
    // don't trigger
    impl ToU64 for FooNoCopy {
        fn to_u64(self) -> u64 {
            2
        }
    }
}

mod issue7032 {
    trait Foo {
        fn from_usize(x: usize) -> Self;
    }
    // don't trigger
    impl Foo for usize {
        fn from_usize(x: usize) -> Self {
            x
        }
    }
}

mod issue7179 {
    pub struct S(i32);

    impl S {
        // don't trigger (`s` is not `self`)
        pub fn from_be(s: Self) -> Self {
            S(i32::from_be(s.0))
        }

        // lint
        pub fn from_be_self(self) -> Self {
            S(i32::from_be(self.0))
        }
    }

    trait T {
        // don't trigger (`s` is not `self`)
        fn from_be(s: Self) -> Self;
        // lint
        fn from_be_self(self) -> Self;
    }

    trait Foo: Sized {
        fn as_byte_slice(slice: &[Self]) -> &[u8];
    }
}
<|endoftext|>


<commit_before>use std::io::Result as IoResult;
use std::io::Read;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::fmt;
use std::error::Error;

/// Reads HTTP chunks and sends back real data.
pub struct ChunksDecoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,

    // data from the start of the current chunk
    buffer: Vec<u8>,
}

#[derive(Debug, Copy, Clone)]
pub struct ChunksError;

impl fmt::Display for ChunksError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for ChunksError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

impl<R> ChunksDecoder<R> where R: Read {
    pub fn new(source: R) -> ChunksDecoder<R> {
        ChunksDecoder {
            source: source,
            remaining_chunks_size: None,
            buffer: Vec::with_capacity(128),
        }
    }
}

impl<R> Read for ChunksDecoder<R> where R: Read {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        // first possibility: we are not in a chunk
        if self.remaining_chunks_size.is_none() {
            // trying the read the chunk size
            let mut chunk_size = Vec::new();

            loop {
                let byte = try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0)));
                if byte == b'\r' {
                    break;
                }

                chunk_size.push(byte);
            }

            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\n' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }

            let chunk_size = match String::from_utf8(chunk_size) {
                Ok(c) => c,
                Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError))
            };

            let chunk_size = match usize::from_str_radix(&chunk_size, 16) {
                Ok(c) => c,
                Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError))
            };

            // if the chunk size is 0, we are at EOF
            if chunk_size == 0 {
                if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\r' {
                    return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
                }
                if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\n' {
                    return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
                }
                return Ok(0);
            }

            // now that we now the current chunk size, calling ourselves recursively
            self.remaining_chunks_size = Some(chunk_size);
            return self.read(buf);
        }

        assert!(self.remaining_chunks_size.is_some());

        // second possibility: we continue reading from a chunk
        if buf.len() < *self.remaining_chunks_size.as_ref().unwrap() {
            let read = try!(self.source.read(buf));
            *self.remaining_chunks_size.as_mut().unwrap() -= read;
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= *self.remaining_chunks_size.as_ref().unwrap());

        let remaining_chunks_size = *self.remaining_chunks_size.as_ref().unwrap();

        let buf = &mut buf[.. remaining_chunks_size];
        let read = try!(self.source.read(buf));
        *self.remaining_chunks_size.as_mut().unwrap() -= read;

        if read == remaining_chunks_size {
            self.remaining_chunks_size = None;

            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\r' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }
            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\n' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }
        }

        return Ok(read);
    }
}

#[cfg(test)]
mod test {
    use super::ChunksDecoder;
    use std::io;
    use std::io::Read;

    #[test]
    fn test() {
        let source = io::Cursor::new("3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    #[should_panic]
    fn invalid_input1() {
        let source = io::Cursor::new("2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();
    }

    #[test]
    #[should_panic]
    fn invalid_input2() {
        let source = io::Cursor::new("3\rhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();
    }
}
<commit_msg>Clean up error handling<commit_after>use std::io::Result as IoResult;
use std::io::Read;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::fmt;
use std::error::Error;

/// Reads HTTP chunks and sends back real data.
pub struct ChunksDecoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,

    // data from the start of the current chunk
    buffer: Vec<u8>,
}

#[derive(Debug, Copy, Clone)]
pub struct ChunksError;

impl fmt::Display for ChunksError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for ChunksError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

impl<R> ChunksDecoder<R> where R: Read {
    pub fn new(source: R) -> ChunksDecoder<R> {
        ChunksDecoder {
            source: source,
            remaining_chunks_size: None,
            buffer: Vec::with_capacity(128),
        }
    }
}

impl<R> Read for ChunksDecoder<R> where R: Read {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        // first possibility: we are not in a chunk
        if self.remaining_chunks_size.is_none() {
            // trying the read the chunk size
            let mut chunk_size = Vec::new();

            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => try!(b),
                    None => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError)),
                };

                if byte == b'\r' {
                    break;
                }

                chunk_size.push(byte);
            }

            match self.source.by_ref().bytes().next() {
                Some(Ok(b'\n')) => (),
                _ => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError)),
            }

            let chunk_size = match String::from_utf8(chunk_size) {
                Ok(c) => c,
                Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError))
            };

            let chunk_size = match usize::from_str_radix(&chunk_size, 16) {
                Ok(c) => c,
                Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError))
            };

            // if the chunk size is 0, we are at EOF
            if chunk_size == 0 {
                if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\r' {
                    return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
                }
                if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\n' {
                    return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
                }
                return Ok(0);
            }

            // now that we now the current chunk size, calling ourselves recursively
            self.remaining_chunks_size = Some(chunk_size);
            return self.read(buf);
        }

        assert!(self.remaining_chunks_size.is_some());

        // second possibility: we continue reading from a chunk
        if buf.len() < *self.remaining_chunks_size.as_ref().unwrap() {
            let read = try!(self.source.read(buf));
            *self.remaining_chunks_size.as_mut().unwrap() -= read;
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= *self.remaining_chunks_size.as_ref().unwrap());

        let remaining_chunks_size = *self.remaining_chunks_size.as_ref().unwrap();

        let buf = &mut buf[.. remaining_chunks_size];
        let read = try!(self.source.read(buf));
        *self.remaining_chunks_size.as_mut().unwrap() -= read;

        if read == remaining_chunks_size {
            self.remaining_chunks_size = None;

            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\r' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }
            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\n' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }
        }

        return Ok(read);
    }
}

#[cfg(test)]
mod test {
    use super::ChunksDecoder;
    use std::io;
    use std::io::Read;

    #[test]
    fn test() {
        let source = io::Cursor::new("3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    #[should_panic]
    fn invalid_input1() {
        let source = io::Cursor::new("2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();
    }

    #[test]
    #[should_panic]
    fn invalid_input2() {
        let source = io::Cursor::new("3\rhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();
    }
}
<|endoftext|>