<commit_before>use std::collections::HashMap;
use std::hash::Hash;

///////////////////////////////////////////////////////////////////////////////

trait Deserialize<S, E> {
    fn deserialize(state: &mut S) -> Result<Self, E>;
}

///////////////////////////////////////////////////////////////////////////////

trait VisitorState<E> {
    fn visit_int(&mut self) -> Result<int, E>;

    fn visit_string(&mut self) -> Result<String, E>;

    fn visit_seq<
        T: Deserialize<Self, E>,
        V: Visitor<T, Self, E>
    >(&mut self) -> Result<T, E>;

    fn visit_seq_elt<
        T: Deserialize<Self, E>,
    >(&mut self) -> Result<T, E>;

    fn visit_map<
        T: Deserialize<Self, E>,
        V: Visitor<T, Self, E>
    >(&mut self) -> Result<T, E>;

    fn visit_map_elt<
        K: Deserialize<Self, E>,
        V: Deserialize<Self, E>
    >(&mut self) -> Result<(K, V), E>;
}

trait Visitor<C, S, E> {
    fn new(len: uint) -> Self;

    fn visit(&mut self, state: &mut S) -> Result<(), E>;

    fn unwrap(self) -> Result<C, E>;
}

///////////////////////////////////////////////////////////////////////////////

impl<S: VisitorState<E>, E> Deserialize<S, E> for int {
    fn deserialize(state: &mut S) -> Result<int, E> {
        state.visit_int()
    }
}

impl<S: VisitorState<E>, E> Deserialize<S, E> for String {
    fn deserialize(state: &mut S) -> Result<String, E> {
        state.visit_string()
    }
}

///////////////////////////////////////////////////////////////////////////////

impl<
    T: Deserialize<S, E>,
    S: VisitorState<E>,
    E
> Deserialize<S, E> for Vec<T> {
    fn deserialize(state: &mut S) -> Result<Vec<T>, E> {
        struct Visitor<T> {
            value: Vec<T>,
        }

        impl<
            T: Deserialize<S, E>,
            S: VisitorState<E>,
            E
        > ::Visitor<Vec<T>, S, E> for Visitor<T> {
            fn new(len: uint) -> Visitor<T> {
                Visitor {
                    value: Vec::with_capacity(len),
                }
            }

            fn visit(&mut self, state: &mut S) -> Result<(), E> {
                let value = try!(state.visit_seq_elt());
                self.value.push(value);
                Ok(())
            }

            fn unwrap(self) -> Result<Vec<T>, E> {
                Ok(self.value)
            }
        }

        state.visit_seq::<Vec<T>, Visitor<T>>()
    }
}

///////////////////////////////////////////////////////////////////////////////

impl<
    T0: Deserialize<S, E>,
    T1: Deserialize<S, E>,
    S: VisitorState<E>,
    E
> Deserialize<S, E> for (T0, T1) {
    fn deserialize(state: &mut S) -> Result<(T0, T1), E> {
        struct Visitor<T0, T1> {
            state: uint,
            t0: Option<T0>,
            t1: Option<T1>,
        }

        impl<
            T0: Deserialize<S, E>,
            T1: Deserialize<S, E>,
            S: VisitorState<E>,
            E
        > ::Visitor<(T0, T1), S, E> for Visitor<T0, T1> {
            fn new(_: uint) -> Visitor<T0, T1> {
                Visitor {
                    state: 0,
                    t0: None,
                    t1: None,
                }
            }

            fn visit(&mut self, state: &mut S) -> Result<(), E> {
                match self.state {
                    0 => {
                        self.state += 1;
                        self.t0 = Some(try!(state.visit_seq_elt()));
                    }
                    1 => {
                        self.state += 1;
                        self.t1 = Some(try!(state.visit_seq_elt()));
                    }
                    _ => fail!()
                }

                Ok(())
            }

            fn unwrap(self) -> Result<(T0, T1), E> {
                let t0 = match self.t0 {
                    Some(t0) => t0,
                    None => { fail!(); }
                };

                let t1 = match self.t1 {
                    Some(t1) => t1,
                    None => { fail!(); }
                };

                Ok((t0, t1))
            }
        }

        state.visit_seq::<(T0, T1), Visitor<T0, T1>>()
    }
}

///////////////////////////////////////////////////////////////////////////////

impl<
    K: Deserialize<S, E> + Eq + Hash,
    V: Deserialize<S, E>,
    S: VisitorState<E>,
    E
> Deserialize<S, E> for HashMap<K, V> {
    fn deserialize(state: &mut S) -> Result<HashMap<K, V>, E> {
        struct Visitor<K, V> {
            value: HashMap<K, V>,
        }

        impl<
            K: Deserialize<S, E> + Eq + Hash,
            V: Deserialize<S, E>,
            S: VisitorState<E>,
            E
        > ::Visitor<HashMap<K, V>, S, E> for Visitor<K, V> {
            fn new(len: uint) -> Visitor<K, V> {
                Visitor {
                    value: HashMap::with_capacity(len),
                }
            }

            fn visit(&mut self, state: &mut S) -> Result<(), E> {
                let (key, value) = try!(state.visit_map_elt());
                self.value.insert(key, value);
                Ok(())
            }

            fn unwrap(self) -> Result<HashMap<K, V>, E> {
                Ok(self.value)
            }
        }

        state.visit_map::<HashMap<K, V>, Visitor<K, V>>()
    }
}

///////////////////////////////////////////////////////////////////////////////

trait Deserializer<S, E> {
    fn deserialize<T: Deserialize<S, E>>(&mut self) -> Result<T, E>;
}

///////////////////////////////////////////////////////////////////////////////

enum Token {
    Int(int),
    String(String),
    SeqStart(uint),
    MapStart(uint),
    End,
}

struct MyDeserializerState<Iter> {
    tokens: Iter,
    peeked: Option<Token>,
}

impl<Iter: Iterator<Token>> MyDeserializerState<Iter> {
    fn new(tokens: Iter) -> MyDeserializerState<Iter> {
        MyDeserializerState {
            tokens: tokens,
            peeked: None,
        }
    }

    fn next(&mut self) -> Option<Token> {
        match self.peeked.take() {
            Some(token) => { return Some(token); }
            None => { }
        }

        self.tokens.next()
    }
}

impl<Iter: Iterator<Token>> VisitorState<()> for MyDeserializerState<Iter> {
    fn visit_int(&mut self) -> Result<int, ()> {
        match self.next() {
            Some(Int(v)) => Ok(v),
            _ => Err(())
        }
    }

    fn visit_string(&mut self) -> Result<String, ()> {
        match self.next() {
            Some(String(v)) => Ok(v),
            _ => Err(())
        }
    }

    fn visit_seq<
        T: Deserialize<MyDeserializerState<Iter>, ()>,
        V: Visitor<T, MyDeserializerState<Iter>, ()>
    >(&mut self) -> Result<T, ()> {
        let len = match self.next() {
            Some(SeqStart(len)) => len,
            _ => { return Err(()); }
        };

        let mut visitor: V = Visitor::new(len);

        loop {
            match self.next() {
                Some(End) => { break; }
                Some(token) => {
                    self.peeked = Some(token);
                    try!(visitor.visit(self));
                }
                _ => { return Err(()); }
            }
        }

        visitor.unwrap()
    }

    fn visit_seq_elt<
        T: Deserialize<MyDeserializerState<Iter>, ()>,
    >(&mut self) -> Result<T, ()> {
        Deserialize::deserialize(self)
    }

    fn visit_map<
        T: Deserialize<MyDeserializerState<Iter>, ()>,
        V: Visitor<T, MyDeserializerState<Iter>, ()>
    >(&mut self) -> Result<T, ()> {
        let len = match self.next() {
            Some(MapStart(len)) => len,
            _ => { return Err(()); }
        };

        let mut visitor: V = Visitor::new(len);

        loop {
            match self.next() {
                Some(End) => { break; }
                Some(token) => {
                    self.peeked = Some(token);
                    try!(visitor.visit(self));
                }
                _ => { return Err(()); }
            }
        }

        visitor.unwrap()
    }

    fn visit_map_elt<
        K: Deserialize<MyDeserializerState<Iter>, ()>,
        V: Deserialize<MyDeserializerState<Iter>, ()>
    >(&mut self) -> Result<(K, V), ()> {
        let k = try!(Deserialize::deserialize(self));
        let v = try!(Deserialize::deserialize(self));
        Ok((k, v))
    }
}

///////////////////////////////////////////////////////////////////////////////

fn main() {
    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End
    );
    let mut state = MyDeserializerState::new(tokens.move_iter());

    let v: Result<Vec<int>, ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);

    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End
    );
    let mut state = MyDeserializerState::new(tokens.move_iter());

    let v: Result<(int, int), ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);

    let tokens = vec!(
        MapStart(2),
        String("a".to_string()),
        Int(1),
        String("b".to_string()),
        Int(2),
        End
    );
    let mut state = MyDeserializerState::new(tokens.move_iter());

    let v: Result<HashMap<String, int>, ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);
}
<commit_msg>playing around with a de2 generic visitor<commit_after>use std::collections::HashMap;
use std::hash::Hash;

///////////////////////////////////////////////////////////////////////////////

trait Deserialize<S, E> {
    fn deserialize(state: &mut S) -> Result<Self, E>;
}

///////////////////////////////////////////////////////////////////////////////

trait VisitorState<E> {
    fn visit<
        V: Visitor<Value, SeqValue, E>,
        Value,
        SeqValue,
    >(&mut self, visitor: &mut V) -> Result<Value, E>;

    fn visit_null(&mut self) -> Result<(), E>;

    fn visit_int(&mut self) -> Result<int, E>;

    fn visit_string(&mut self) -> Result<String, E>;

    fn visit_seq(&mut self) -> Result<uint, E>;

    fn visit_seq_elt<
        T: Deserialize<Self, E>,
    >(&mut self) -> Option<Result<T, E>>;

    /*
    fn visit_map<
        T: Deserialize<Self, E>,
        V: Visitor<T, Self, E>
    >(&mut self) -> Result<T, E>;

    fn visit_map_elt<
        K: Deserialize<Self, E>,
        V: Deserialize<Self, E>
    >(&mut self) -> Result<(K, V), E>;
    */
}

trait Visitor<Value, SeqValue, E> {
    fn visit_null(&mut self) -> Result<Value, E>;

    fn visit_int(&mut self, v: int) -> Result<Value, E>;

    fn visit_string(&mut self, v: String) -> Result<Value, E>;

    fn visit_seq(&mut self, len: uint) -> Result<SeqValue, E>;

    fn visit_seq_elt(&mut self, values: &mut SeqValue, value: Value) -> Result<(), E>;

    fn visit_seq_end(&mut self, values: SeqValue) -> Result<Value, E>;
}

/*
trait Visitor<VS: VisitorState<Self, E>, E> {
    fn next<
        T: Deserialize<VS, E>,
    >(&mut self) -> Option<Result<T, E>>;

    fn size_hint(&self) -> (uint, Option<uint>);
}
*/

/*
trait Visitor<C, S, E> {
    fn new(len: uint) -> Self;

    fn visit(&mut self, state: &mut S) -> Result<(), E>;

    fn unwrap(self) -> Result<C, E>;
}
*/

///////////////////////////////////////////////////////////////////////////////

impl<
    S: VisitorState<E>,
    E,
> Deserialize<S, E> for int {
    fn deserialize(state: &mut S) -> Result<int, E> {
        state.visit_int()
    }
}

impl<
    S: VisitorState<E>,
    E,
> Deserialize<S, E> for String {
    fn deserialize(state: &mut S) -> Result<String, E> {
        state.visit_string()
    }
}

///////////////////////////////////////////////////////////////////////////////

impl<
    T: Deserialize<S, E>,
    S: VisitorState<E>,
    E,
> Deserialize<S, E> for Vec<T> {
    fn deserialize(state: &mut S) -> Result<Vec<T>, E> {
        let len = try!(state.visit_seq());
        let mut value = Vec::with_capacity(len);

        loop {
            match state.visit_seq_elt() {
                Some(Ok(v)) => { value.push(v); }
                Some(Err(err)) => { return Err(err); }
                None => { break; }
            }
        }

        Ok(value)
    }
}

///////////////////////////////////////////////////////////////////////////////

impl<
    S: VisitorState<E>,
    E
> Deserialize<S, E> for () {
    fn deserialize(state: &mut S) -> Result<(), E> {
        state.visit_null()
    }
}

///////////////////////////////////////////////////////////////////////////////

impl<
    T0: Deserialize<S, E>,
    T1: Deserialize<S, E>,
    S: VisitorState<E>,
    E
> Deserialize<S, E> for (T0, T1) {
    fn deserialize(state: &mut S) -> Result<(T0, T1), E> {
        let _ = try!(state.visit_seq());

        let t0 = match state.visit_seq_elt() {
            Some(Ok(v)) => v,
            Some(Err(err)) => { return Err(err); }
            None => { fail!(); }
        };

        let t1 = match state.visit_seq_elt() {
            Some(Ok(v)) => v,
            Some(Err(err)) => { return Err(err); }
            None => { fail!(); }
        };

        match state.visit_seq_elt() {
            Some(Ok(())) => { fail!(); }
            Some(Err(err)) => { return Err(err); }
            None => { }
        }

        Ok((t0, t1))

        /*
        struct Visitor<T0, T1> {
            state: uint,
            t0: Option<T0>,
            t1: Option<T1>,
        }

        impl<
            T0: Deserialize<S, E>,
            T1: Deserialize<S, E>,
            S: VisitorState<E>,
            E
        > ::Visitor<(T0, T1), S, E> for Visitor<T0, T1> {
            fn new(_: uint) -> Visitor<T0, T1> {
                Visitor {
                    state: 0,
                    t0: None,
                    t1: None,
                }
            }

            fn visit(&mut self, state: &mut S) -> Result<(), E> {
                match self.state {
                    0 => {
                        self.state += 1;
                        self.t0 = Some(try!(state.visit_seq_elt()));
                    }
                    1 => {
                        self.state += 1;
                        self.t1 = Some(try!(state.visit_seq_elt()));
                    }
                    _ => fail!()
                }

                Ok(())
            }

            fn unwrap(self) -> Result<(T0, T1), E> {
                let t0 = match self.t0 {
                    Some(t0) => t0,
                    None => { fail!(); }
                };

                let t1 = match self.t1 {
                    Some(t1) => t1,
                    None => { fail!(); }
                };

                Ok((t0, t1))
            }
        }

        state.visit_seq::<(T0, T1), Visitor<T0, T1>>()
        */
    }
}

/*
///////////////////////////////////////////////////////////////////////////////

impl<
    K: Deserialize<S, E> + Eq + Hash,
    V: Deserialize<S, E>,
    S: VisitorState<E>,
    E
> Deserialize<S, E> for HashMap<K, V> {
    fn deserialize(state: &mut S) -> Result<HashMap<K, V>, E> {
        struct Visitor<K, V> {
            value: HashMap<K, V>,
        }

        impl<
            K: Deserialize<S, E> + Eq + Hash,
            V: Deserialize<S, E>,
            S: VisitorState<E>,
            E
        > ::Visitor<HashMap<K, V>, S, E> for Visitor<K, V> {
            fn new(len: uint) -> Visitor<K, V> {
                Visitor {
                    value: HashMap::with_capacity(len),
                }
            }

            fn visit(&mut self, state: &mut S) -> Result<(), E> {
                let (key, value) = try!(state.visit_map_elt());
                self.value.insert(key, value);
                Ok(())
            }

            fn unwrap(self) -> Result<HashMap<K, V>, E> {
                Ok(self.value)
            }
        }

        state.visit_map::<HashMap<K, V>, Visitor<K, V>>()
    }
}
*/

///////////////////////////////////////////////////////////////////////////////

mod json {
    enum Value {
        Null,
        Bool(bool),
        Int(int),
        String(String),
        Vec(Vec<Value>),
    }

    impl<
        S: super::VisitorState<E>,
        E
    > super::Deserialize<S, E> for Value {
        fn deserialize(state: &mut S) -> Result<Value, E> {
            struct Visitor;

            impl<E> super::Visitor<Value, Vec<Value>, E> for Visitor {
                fn visit_null(&mut self) -> Result<Value, E> {
                    Ok(Null)
                }

                fn visit_int(&mut self, v: int) -> Result<Value, E> {
                    Ok(Int(v))
                }

                fn visit_string(&mut self, v: String) -> Result<Value, E> {
                    Ok(String(v))
                }

                fn visit_seq(&mut self, len: uint) -> Result<Vec<Value>, E> {
                    Ok(Vec::with_capacity(len))
                }

                fn visit_seq_elt(&mut self, values: &mut Vec<Value>, value: Value) -> Result<(), E> {
                    values.push(value);
                    Ok(())
                }

                fn visit_seq_end(&mut self, values: Vec<Value>) -> Result<Value, E> {
                    Ok(Vec(values))
                }
            }

            state.visit(&mut Visitor)
        }
    }

}

///////////////////////////////////////////////////////////////////////////////

trait Deserializer<S, E> {
    fn deserialize<T: Deserialize<S, E>>(&mut self) -> Result<T, E>;
}

///////////////////////////////////////////////////////////////////////////////

enum Token {
    Null,
    Int(int),
    String(String),
    SeqStart(uint),
    MapStart(uint),
    End,
}

///////////////////////////////////////////////////////////////////////////////

struct MyDeserializerState<Iter> {
    tokens: Iter,
    peeked: Option<Token>,
}

impl<Iter: Iterator<Token>> MyDeserializerState<Iter> {
    fn new(tokens: Iter) -> MyDeserializerState<Iter> {
        MyDeserializerState {
            tokens: tokens,
            peeked: None,
        }
    }

    fn next(&mut self) -> Option<Token> {
        match self.peeked.take() {
            Some(token) => { return Some(token); }
            None => { }
        }

        self.tokens.next()
    }

    fn peek<'a>(&'a mut self) -> Option<&'a Token> {
        match self.peeked {
            Some(_) => { }
            None => { self.peeked = self.tokens.next(); }
        }

        self.peeked.as_ref()
    }
}

impl<
    'a,
    Iter: Iterator<Token>,
> VisitorState<
    (),
> for MyDeserializerState<Iter> {
    fn visit<
        V: Visitor<Value, SeqValue, ()>,
        Value,
        SeqValue,
    >(&mut self, visitor: &mut V) -> Result<Value, ()> {
        match self.next() {
            Some(Null) => {
                visitor.visit_null()
            }
            Some(Int(v)) => {
                visitor.visit_int(v)
            }
            Some(String(v)) => {
                visitor.visit_string(v)
            }
            Some(SeqStart(len)) => {
                let mut state = try!(visitor.visit_seq(len));

                loop {
                    match self.peek() {
                        Some(&End) => {
                            self.next();
                            break;
                        }
                        Some(_) => {
                            let value = try!(self.visit(visitor));
                            try!(visitor.visit_seq_elt(&mut state, value));
                        }
                        None => {
                            return Err(());
                        }
                    }
                }

                visitor.visit_seq_end(state)
            }
            Some(MapStart(len)) => {
                Err(())
            }
            Some(End) => {
                Err(())
            }
            None => {
                Err(())
            }
        }

    }

    fn visit_null(&mut self) -> Result<(), ()> {
        match self.next() {
            Some(Null) => Ok(()),
            _ => Err(())
        }
    }

    fn visit_int(&mut self) -> Result<int, ()> {
        match self.next() {
            Some(Int(v)) => Ok(v),
            _ => Err(())
        }
    }

    fn visit_string(&mut self) -> Result<String, ()> {
        match self.next() {
            Some(String(v)) => Ok(v),
            _ => Err(())
        }
    }

    fn visit_seq(&mut self) -> Result<uint, ()> {
        match self.next() {
            Some(SeqStart(len)) => Ok(len),
            _ => Err(()),
        }
    }

    fn visit_seq_elt<
        T: Deserialize<MyDeserializerState<Iter>, ()>,
    >(&mut self) -> Option<Result<T, ()>> {
        match self.peek() {
            Some(&End) => {
                self.next();
                None
            }
            Some(_) => {
                Some(Deserialize::deserialize(self))
            }
            None => {
                Some(Err(()))
            }
        }
    }

    /*
    fn visit_map<
        T: Deserialize<MyDeserializerState<Iter>, ()>,
        V: Visitor<T, MyDeserializerState<Iter>, ()>
    >(&mut self) -> Result<T, ()> {
        let len = match self.next() {
            Some(MapStart(len)) => len,
            _ => { return Err(()); }
        };

        let mut visitor: V = Visitor::new(len);

        loop {
            match self.next() {
                Some(End) => { break; }
                Some(token) => {
                    self.peeked = Some(token);
                    try!(visitor.visit(self));
                }
                _ => { return Err(()); }
            }
        }

        visitor.unwrap()
    }

    fn visit_map_elt<
        K: Deserialize<MyDeserializerState<Iter>, ()>,
        V: Deserialize<MyDeserializerState<Iter>, ()>
    >(&mut self) -> Result<(K, V), ()> {
        let k = try!(Deserialize::deserialize(self));
        let v = try!(Deserialize::deserialize(self));
        Ok((k, v))
    }
    */
}

///////////////////////////////////////////////////////////////////////////////

fn main() {
    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End
    );
    let mut state = MyDeserializerState::new(tokens.move_iter());

    let v: Result<Vec<int>, ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);

    let tokens = vec!(
        SeqStart(2),
        Int(1),
        Int(2),
        End
    );
    let mut state = MyDeserializerState::new(tokens.move_iter());

    let v: Result<(int, int), ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);

    /*
    let tokens = vec!(
        MapStart(2),
        String("a".to_string()),
        Int(1),
        String("b".to_string()),
        Int(2),
        End
    );
    let mut state = MyDeserializerState::new(tokens.move_iter());

    let v: Result<HashMap<String, int>, ()> = Deserialize::deserialize(&mut state);
    println!("{}", v);
    */
}
<|endoftext|>


<commit_before>fn main() {
    let immutable_variable = 1;
    let mut mutable_variable = 1;

    // Ok
    mutable_variable += 1;

    // Error!
    immutable_variable += 1;
}
<commit_msg>variables/mut: add prints<commit_after>fn main() {
    let _immutable_variable = 1;
    let mut mutable_variable = 1;

    println!("Before mutation: {}", mutable_variable);

    // Ok
    mutable_variable += 1;

    println!("After mutation: {}", mutable_variable);

    // Error!
    _immutable_variable += 1;
    // FIXME ^ Comment out this line
}
<|endoftext|>


<commit_before>// structs3.rs
// Structs contain more than simply some data, they can also have logic, in this
// exercise we have defined the Package struct and we want to test some logic attached to it,
// make the code compile and the tests pass! If you have issues execute `rustlings hint structs3`

// I AM NOT DONE

#[derive(Debug)]
struct Package {
    from: String,
    to: String,
    weight: f32
}

impl Package {
    fn new(from: String, to: String, weight: f32) -> Package {
        if weight <= 0.0 {
            // Something goes here...
        } else {
            return Package {from, to, weight};
        }
    }

    fn is_international(&self) -> ??? {
        // Something goes here...
    }

    fn get_fees(&self, cost_per_kg: f32) -> ??? {
        // Something goes here...
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[should_panic]
    fn fail_creating_weightless_package() {
        let country_from = String::from("Spain");
        let country_to = String::from("Austria");

        Package::new(country_from, country_to, -2.21);
    }

    #[test]
    fn create_international_package() {
        let country_from = String::from("Spain");
        let country_to = String::from("Russia");

        let package = Package::new(country_from, country_to, 1.2);

        assert!(package.is_international());
    }

    #[test]
    fn calculate_transport_fees() {
        let country_from = String::from("Spain");
        let country_to = String::from("Spain");

        let country_fee = ???;

        let package = Package::new(country_from, country_to, 22.0);

        assert_eq!(package.get_fees(country_fee), 176.0);
    }
}
<commit_msg>fix : Use of integer for prices, therefore also for weight rename confusing "from" and "to" to sender_country and recipient_country as suggested<commit_after>// structs3.rs
// Structs contain more than simply some data, they can also have logic, in this
// exercise we have defined the Package struct and we want to test some logic attached to it,
// make the code compile and the tests pass! If you have issues execute `rustlings hint structs3`

// I AM NOT DONE

#[derive(Debug)]
struct Package {
    sender_country: String,
    recipient_country: String,
    weight_in_grams: i32,
}

impl Package {
    fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
        if weight_in_grams <= 0 {
            // Something goes here...
        } else {
            return Package {sender_country, recipient_country, weight_in_grams};
        }
    }

    fn is_international(&self) -> ??? {
        // Something goes here...
    }

    fn get_fees(&self, cents_per_kg: i32) -> ??? {
        // Something goes here... (beware of grams to kg conversion)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[should_panic]
    fn fail_creating_weightless_package() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Austria");

        Package::new(sender_country, recipient_country, -2210);
    }

    #[test]
    fn create_international_package() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Russia");

        let package = Package::new(sender_country, recipient_country, 1200);

        assert!(package.is_international());
    }

    #[test]
    fn calculate_transport_fees() {
        let sender_country = String::from("Spain");
        let recipient_country = String::from("Spain");

        let cents_per_kg = ???;

        let package = Package::new(sender_country, recipient_country, 1500);

        assert_eq!(package.get_fees(cents_per_kg), 4500);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Liberally derived from the [Firefox JS implementation]
//! (http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/webbrowser.js).
//! Connection point for remote devtools that wish to investigate a particular Browsing Context's contents.
//! Supports dynamic attaching and detaching which control notifications of navigation, etc.

use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::emulation::EmulationActor;
use crate::actors::inspector::InspectorActor;
use crate::actors::performance::PerformanceActor;
use crate::actors::profiler::ProfilerActor;
use crate::actors::root::RootActor;
use crate::actors::stylesheets::StyleSheetsActor;
use crate::actors::thread::ThreadActor;
use crate::actors::timeline::TimelineActor;
use crate::protocol::JsonPacketStream;
use devtools_traits::DevtoolScriptControlMsg::{self, WantsLiveNotifications};
use devtools_traits::DevtoolsPageInfo;
use devtools_traits::NavigationState;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{BrowsingContextId, PipelineId};
use serde_json::{Map, Value};
use std::cell::{Cell, RefCell};
use std::net::TcpStream;

#[derive(Serialize)]
struct BrowsingContextTraits {
    isBrowsingContext: bool,
}

#[derive(Serialize)]
struct AttachedTraits {
    reconfigure: bool,
    frames: bool,
    logInPage: bool,
    canRewind: bool,
    watchpoints: bool,
}

#[derive(Serialize)]
struct BrowsingContextAttachedReply {
    from: String,
    #[serde(rename = "type")]
    type_: String,
    threadActor: String,
    cacheDisabled: bool,
    javascriptEnabled: bool,
    traits: AttachedTraits,
}

#[derive(Serialize)]
struct BrowsingContextDetachedReply {
    from: String,
    #[serde(rename = "type")]
    type_: String,
}

#[derive(Serialize)]
struct ReconfigureReply {
    from: String,
}

#[derive(Serialize)]
struct ListFramesReply {
    from: String,
    frames: Vec<FrameMsg>,
}

#[derive(Serialize)]
struct FrameMsg {
    id: u32,
    url: String,
    title: String,
    parentID: u32,
}

#[derive(Serialize)]
struct ListWorkersReply {
    from: String,
    workers: Vec<WorkerMsg>,
}

#[derive(Serialize)]
struct WorkerMsg {
    id: u32,
}

#[derive(Serialize)]
pub struct BrowsingContextActorMsg {
    actor: String,
    title: String,
    url: String,
    outerWindowID: u32,
    browsingContextId: u32,
    consoleActor: String,
    emulationActor: String,
    inspectorActor: String,
    timelineActor: String,
    profilerActor: String,
    performanceActor: String,
    styleSheetsActor: String,
    traits: BrowsingContextTraits,
    // Part of the official protocol, but not yet implemented.
    /*storageActor: String,
    memoryActor: String,
    framerateActor: String,
    reflowActor: String,
    cssPropertiesActor: String,
    animationsActor: String,
    webExtensionInspectedWindowActor: String,
    accessibilityActor: String,
    screenshotActor: String,
    changesActor: String,
    webSocketActor: String,
    manifestActor: String,*/
}

pub struct BrowsingContextActor {
    pub name: String,
    pub title: String,
    pub url: String,
    pub console: String,
    pub emulation: String,
    pub inspector: String,
    pub timeline: String,
    pub profiler: String,
    pub performance: String,
    pub styleSheets: String,
    pub thread: String,
    pub streams: RefCell<Vec<TcpStream>>,
    pub browsing_context_id: BrowsingContextId,
    pub active_pipeline: Cell<PipelineId>,
    pub script_chan: IpcSender<DevtoolScriptControlMsg>,
}

impl Actor for BrowsingContextActor {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn handle_message(
        &self,
        _registry: &ActorRegistry,
        msg_type: &str,
        msg: &Map<String, Value>,
        stream: &mut TcpStream,
    ) -> Result<ActorMessageStatus, ()> {
        Ok(match msg_type {
            "reconfigure" => {
                if let Some(options) = msg.get("options").and_then(|o| o.as_object()) {
                    if let Some(val) = options.get("performReload") {
                        if val.as_bool().unwrap_or(false) {
                            let _ = self
                                .script_chan
                                .send(DevtoolScriptControlMsg::Reload(self.active_pipeline.get()));
                        }
                    }
                }
                stream.write_json_packet(&ReconfigureReply { from: self.name() });
                ActorMessageStatus::Processed
            },

            // https://docs.firefox-dev.tools/backend/protocol.html#listing-browser-tabs
            // (see "To attach to a _targetActor_")
            "attach" => {
                let msg = BrowsingContextAttachedReply {
                    from: self.name(),
                    type_: "tabAttached".to_owned(),
                    threadActor: self.thread.clone(),
                    cacheDisabled: false,
                    javascriptEnabled: true,
                    traits: AttachedTraits {
                        reconfigure: false,
                        frames: false,
                        logInPage: false,
                        canRewind: false,
                        watchpoints: false,
                    },
                };
                self.streams.borrow_mut().push(stream.try_clone().unwrap());
                stream.write_json_packet(&msg);
                self.script_chan
                    .send(WantsLiveNotifications(self.active_pipeline.get(), true))
                    .unwrap();
                ActorMessageStatus::Processed
            },

            //FIXME: The current implementation won't work for multiple connections. Need to ensure
            //       that the correct stream is removed.
            "detach" => {
                let msg = BrowsingContextDetachedReply {
                    from: self.name(),
                    type_: "detached".to_owned(),
                };
                self.streams.borrow_mut().pop();
                stream.write_json_packet(&msg);
                self.script_chan
                    .send(WantsLiveNotifications(self.active_pipeline.get(), false))
                    .unwrap();
                ActorMessageStatus::Processed
            },

            "listFrames" => {
                let msg = ListFramesReply {
                    from: self.name(),
                    frames: vec![FrameMsg {
                        id: 0, //FIXME should match outerwindow id
                        parentID: 0,
                        url: self.url.clone(),
                        title: self.title.clone(),
                    }],
                };
                stream.write_json_packet(&msg);
                ActorMessageStatus::Processed
            },

            "listWorkers" => {
                let msg = ListWorkersReply {
                    from: self.name(),
                    workers: vec![],
                };
                stream.write_json_packet(&msg);
                ActorMessageStatus::Processed
            },

            _ => ActorMessageStatus::Ignored,
        })
    }
}

impl BrowsingContextActor {
    pub(crate) fn new(
        console: String,
        id: BrowsingContextId,
        page_info: DevtoolsPageInfo,
        pipeline: PipelineId,
        script_sender: IpcSender<DevtoolScriptControlMsg>,
        actors: &mut ActorRegistry,
    ) -> BrowsingContextActor {
        let emulation = EmulationActor::new(actors.new_name("emulation"));

        let name = actors.new_name("target");

        let inspector = InspectorActor {
            name: actors.new_name("inspector"),
            walker: RefCell::new(None),
            pageStyle: RefCell::new(None),
            highlighter: RefCell::new(None),
            script_chan: script_sender.clone(),
            browsing_context: name.clone(),
        };

        let timeline =
            TimelineActor::new(actors.new_name("timeline"), pipeline, script_sender.clone());

        let profiler = ProfilerActor::new(actors.new_name("profiler"));
        let performance = PerformanceActor::new(actors.new_name("performance"));

        // the strange switch between styleSheets and stylesheets is due
        // to an inconsistency in devtools. See Bug #1498893 in bugzilla
        let styleSheets = StyleSheetsActor::new(actors.new_name("stylesheets"));
        let thread = ThreadActor::new(actors.new_name("context"));

        let DevtoolsPageInfo { title, url } = page_info;
        let target = BrowsingContextActor {
            name: name,
            script_chan: script_sender,
            title: String::from(title),
            url: url.into_string(),
            console: console,
            emulation: emulation.name(),
            inspector: inspector.name(),
            timeline: timeline.name(),
            profiler: profiler.name(),
            performance: performance.name(),
            styleSheets: styleSheets.name(),
            thread: thread.name(),
            streams: RefCell::new(Vec::new()),
            browsing_context_id: id,
            active_pipeline: Cell::new(pipeline),
        };

        actors.register(Box::new(emulation));
        actors.register(Box::new(inspector));
        actors.register(Box::new(timeline));
        actors.register(Box::new(profiler));
        actors.register(Box::new(performance));
        actors.register(Box::new(styleSheets));
        actors.register(Box::new(thread));

        let root = actors.find_mut::<RootActor>("root");
        root.tabs.push(target.name.clone());
        target
    }

    pub fn encodable(&self) -> BrowsingContextActorMsg {
        BrowsingContextActorMsg {
            actor: self.name(),
            traits: BrowsingContextTraits {
                isBrowsingContext: true,
            },
            title: self.title.clone(),
            url: self.url.clone(),
            //FIXME: shouldn't ignore pipeline namespace field
            browsingContextId: self.browsing_context_id.index.0.get(),
            //FIXME: shouldn't ignore pipeline namespace field
            outerWindowID: self.active_pipeline.get().index.0.get(),
            consoleActor: self.console.clone(),
            emulationActor: self.emulation.clone(),
            inspectorActor: self.inspector.clone(),
            timelineActor: self.timeline.clone(),
            profilerActor: self.profiler.clone(),
            performanceActor: self.performance.clone(),
            styleSheetsActor: self.styleSheets.clone(),
        }
    }

    pub(crate) fn navigate(&self, state: NavigationState) {
        let (pipeline, title, url, state) = match state {
            NavigationState::Start(url) => (None, None, url, "start"),
            NavigationState::Stop(pipeline, info) => {
                (Some(pipeline), Some(info.title), info.url, "stop")
            },
        };
        if let Some(p) = pipeline {
            self.active_pipeline.set(p);
        }
        let msg = TabNavigated {
            from: self.name(),
            type_: "tabNavigated".to_owned(),
            url: url.as_str().to_owned(),
            title: title,
            nativeConsoleAPI: true,
            state: state.to_owned(),
            isFrameSwitching: false,
        };
        for stream in &mut *self.streams.borrow_mut() {
            stream.write_json_packet(&msg);
        }
    }
}

#[derive(Serialize)]
struct TabNavigated {
    from: String,
    #[serde(rename = "type")]
    type_: String,
    url: String,
    title: Option<String>,
    nativeConsoleAPI: bool,
    state: String,
    isFrameSwitching: bool,
}
<commit_msg>Update browsing context title/url when navigating.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

//! Liberally derived from the [Firefox JS implementation]
//! (http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/webbrowser.js).
//! Connection point for remote devtools that wish to investigate a particular Browsing Context's contents.
//! Supports dynamic attaching and detaching which control notifications of navigation, etc.

use crate::actor::{Actor, ActorMessageStatus, ActorRegistry};
use crate::actors::emulation::EmulationActor;
use crate::actors::inspector::InspectorActor;
use crate::actors::performance::PerformanceActor;
use crate::actors::profiler::ProfilerActor;
use crate::actors::root::RootActor;
use crate::actors::stylesheets::StyleSheetsActor;
use crate::actors::thread::ThreadActor;
use crate::actors::timeline::TimelineActor;
use crate::protocol::JsonPacketStream;
use devtools_traits::DevtoolScriptControlMsg::{self, WantsLiveNotifications};
use devtools_traits::DevtoolsPageInfo;
use devtools_traits::NavigationState;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{BrowsingContextId, PipelineId};
use serde_json::{Map, Value};
use std::cell::{Cell, RefCell};
use std::net::TcpStream;

#[derive(Serialize)]
struct BrowsingContextTraits {
    isBrowsingContext: bool,
}

#[derive(Serialize)]
struct AttachedTraits {
    reconfigure: bool,
    frames: bool,
    logInPage: bool,
    canRewind: bool,
    watchpoints: bool,
}

#[derive(Serialize)]
struct BrowsingContextAttachedReply {
    from: String,
    #[serde(rename = "type")]
    type_: String,
    threadActor: String,
    cacheDisabled: bool,
    javascriptEnabled: bool,
    traits: AttachedTraits,
}

#[derive(Serialize)]
struct BrowsingContextDetachedReply {
    from: String,
    #[serde(rename = "type")]
    type_: String,
}

#[derive(Serialize)]
struct ReconfigureReply {
    from: String,
}

#[derive(Serialize)]
struct ListFramesReply {
    from: String,
    frames: Vec<FrameMsg>,
}

#[derive(Serialize)]
struct FrameMsg {
    id: u32,
    url: String,
    title: String,
    parentID: u32,
}

#[derive(Serialize)]
struct ListWorkersReply {
    from: String,
    workers: Vec<WorkerMsg>,
}

#[derive(Serialize)]
struct WorkerMsg {
    id: u32,
}

#[derive(Serialize)]
pub struct BrowsingContextActorMsg {
    actor: String,
    title: String,
    url: String,
    outerWindowID: u32,
    browsingContextId: u32,
    consoleActor: String,
    emulationActor: String,
    inspectorActor: String,
    timelineActor: String,
    profilerActor: String,
    performanceActor: String,
    styleSheetsActor: String,
    traits: BrowsingContextTraits,
    // Part of the official protocol, but not yet implemented.
    /*storageActor: String,
    memoryActor: String,
    framerateActor: String,
    reflowActor: String,
    cssPropertiesActor: String,
    animationsActor: String,
    webExtensionInspectedWindowActor: String,
    accessibilityActor: String,
    screenshotActor: String,
    changesActor: String,
    webSocketActor: String,
    manifestActor: String,*/
}

pub struct BrowsingContextActor {
    pub name: String,
    pub title: RefCell<String>,
    pub url: RefCell<String>,
    pub console: String,
    pub emulation: String,
    pub inspector: String,
    pub timeline: String,
    pub profiler: String,
    pub performance: String,
    pub styleSheets: String,
    pub thread: String,
    pub streams: RefCell<Vec<TcpStream>>,
    pub browsing_context_id: BrowsingContextId,
    pub active_pipeline: Cell<PipelineId>,
    pub script_chan: IpcSender<DevtoolScriptControlMsg>,
}

impl Actor for BrowsingContextActor {
    fn name(&self) -> String {
        self.name.clone()
    }

    fn handle_message(
        &self,
        _registry: &ActorRegistry,
        msg_type: &str,
        msg: &Map<String, Value>,
        stream: &mut TcpStream,
    ) -> Result<ActorMessageStatus, ()> {
        Ok(match msg_type {
            "reconfigure" => {
                if let Some(options) = msg.get("options").and_then(|o| o.as_object()) {
                    if let Some(val) = options.get("performReload") {
                        if val.as_bool().unwrap_or(false) {
                            let _ = self
                                .script_chan
                                .send(DevtoolScriptControlMsg::Reload(self.active_pipeline.get()));
                        }
                    }
                }
                stream.write_json_packet(&ReconfigureReply { from: self.name() });
                ActorMessageStatus::Processed
            },

            // https://docs.firefox-dev.tools/backend/protocol.html#listing-browser-tabs
            // (see "To attach to a _targetActor_")
            "attach" => {
                let msg = BrowsingContextAttachedReply {
                    from: self.name(),
                    type_: "tabAttached".to_owned(),
                    threadActor: self.thread.clone(),
                    cacheDisabled: false,
                    javascriptEnabled: true,
                    traits: AttachedTraits {
                        reconfigure: false,
                        frames: true,
                        logInPage: false,
                        canRewind: false,
                        watchpoints: false,
                    },
                };
                self.streams.borrow_mut().push(stream.try_clone().unwrap());
                stream.write_json_packet(&msg);
                self.script_chan
                    .send(WantsLiveNotifications(self.active_pipeline.get(), true))
                    .unwrap();
                ActorMessageStatus::Processed
            },

            //FIXME: The current implementation won't work for multiple connections. Need to ensure
            //       that the correct stream is removed.
            "detach" => {
                let msg = BrowsingContextDetachedReply {
                    from: self.name(),
                    type_: "detached".to_owned(),
                };
                self.streams.borrow_mut().pop();
                stream.write_json_packet(&msg);
                self.script_chan
                    .send(WantsLiveNotifications(self.active_pipeline.get(), false))
                    .unwrap();
                ActorMessageStatus::Processed
            },

            "listFrames" => {
                let msg = ListFramesReply {
                    from: self.name(),
                    frames: vec![FrameMsg {
                        //FIXME: shouldn't ignore pipeline namespace field
                        id: self.active_pipeline.get().index.0.get(),
                        parentID: 0,
                        url: self.url.borrow().clone(),
                        title: self.title.borrow().clone(),
                    }],
                };
                stream.write_json_packet(&msg);
                ActorMessageStatus::Processed
            },

            "listWorkers" => {
                let msg = ListWorkersReply {
                    from: self.name(),
                    workers: vec![],
                };
                stream.write_json_packet(&msg);
                ActorMessageStatus::Processed
            },

            _ => ActorMessageStatus::Ignored,
        })
    }
}

impl BrowsingContextActor {
    pub(crate) fn new(
        console: String,
        id: BrowsingContextId,
        page_info: DevtoolsPageInfo,
        pipeline: PipelineId,
        script_sender: IpcSender<DevtoolScriptControlMsg>,
        actors: &mut ActorRegistry,
    ) -> BrowsingContextActor {
        let emulation = EmulationActor::new(actors.new_name("emulation"));

        let name = actors.new_name("target");

        let inspector = InspectorActor {
            name: actors.new_name("inspector"),
            walker: RefCell::new(None),
            pageStyle: RefCell::new(None),
            highlighter: RefCell::new(None),
            script_chan: script_sender.clone(),
            browsing_context: name.clone(),
        };

        let timeline =
            TimelineActor::new(actors.new_name("timeline"), pipeline, script_sender.clone());

        let profiler = ProfilerActor::new(actors.new_name("profiler"));
        let performance = PerformanceActor::new(actors.new_name("performance"));

        // the strange switch between styleSheets and stylesheets is due
        // to an inconsistency in devtools. See Bug #1498893 in bugzilla
        let styleSheets = StyleSheetsActor::new(actors.new_name("stylesheets"));
        let thread = ThreadActor::new(actors.new_name("context"));

        let DevtoolsPageInfo { title, url } = page_info;
        let target = BrowsingContextActor {
            name: name,
            script_chan: script_sender,
            title: RefCell::new(String::from(title)),
            url: RefCell::new(url.into_string()),
            console: console,
            emulation: emulation.name(),
            inspector: inspector.name(),
            timeline: timeline.name(),
            profiler: profiler.name(),
            performance: performance.name(),
            styleSheets: styleSheets.name(),
            thread: thread.name(),
            streams: RefCell::new(Vec::new()),
            browsing_context_id: id,
            active_pipeline: Cell::new(pipeline),
        };

        actors.register(Box::new(emulation));
        actors.register(Box::new(inspector));
        actors.register(Box::new(timeline));
        actors.register(Box::new(profiler));
        actors.register(Box::new(performance));
        actors.register(Box::new(styleSheets));
        actors.register(Box::new(thread));

        let root = actors.find_mut::<RootActor>("root");
        root.tabs.push(target.name.clone());
        target
    }

    pub fn encodable(&self) -> BrowsingContextActorMsg {
        BrowsingContextActorMsg {
            actor: self.name(),
            traits: BrowsingContextTraits {
                isBrowsingContext: true,
            },
            title: self.title.borrow().clone(),
            url: self.url.borrow().clone(),
            //FIXME: shouldn't ignore pipeline namespace field
            browsingContextId: self.browsing_context_id.index.0.get(),
            //FIXME: shouldn't ignore pipeline namespace field
            outerWindowID: self.active_pipeline.get().index.0.get(),
            consoleActor: self.console.clone(),
            emulationActor: self.emulation.clone(),
            inspectorActor: self.inspector.clone(),
            timelineActor: self.timeline.clone(),
            profilerActor: self.profiler.clone(),
            performanceActor: self.performance.clone(),
            styleSheetsActor: self.styleSheets.clone(),
        }
    }

    pub(crate) fn navigate(&self, state: NavigationState) {
        let (pipeline, title, url, state) = match state {
            NavigationState::Start(url) => (None, None, url, "start"),
            NavigationState::Stop(pipeline, info) => {
                (Some(pipeline), Some(info.title), info.url, "stop")
            },
        };
        if let Some(p) = pipeline {
            self.active_pipeline.set(p);
        }
        *self.url.borrow_mut() = url.as_str().to_owned();
        if let Some(ref t) = title {
            *self.title.borrow_mut() = t.clone();
        }

        let msg = TabNavigated {
            from: self.name(),
            type_: "tabNavigated".to_owned(),
            url: url.as_str().to_owned(),
            title: title,
            nativeConsoleAPI: true,
            state: state.to_owned(),
            isFrameSwitching: false,
        };
        for stream in &mut *self.streams.borrow_mut() {
            stream.write_json_packet(&msg);
        }
    }
}

#[derive(Serialize)]
struct TabNavigated {
    from: String,
    #[serde(rename = "type")]
    type_: String,
    url: String,
    title: Option<String>,
    nativeConsoleAPI: bool,
    state: String,
    isFrameSwitching: bool,
}
<|endoftext|>


<commit_before>use cripes::symbol::{Pool,Type,Unpacked,Inline,PackFormat};
use std::string::String;

macro_rules! inline_test_strings {
    () => ((0u8..16u8).map(|i| (0u8..i).map(|j| (j  + 'a' as u8) as char).collect::<String>()));
}

#[test]
fn inline_as_slice() {
    for s in inline_test_strings!() {
        let sym = Inline::new(s.as_slice());
        assert_eq!(sym.as_slice(), s.as_slice());
    }
}

#[test]
fn inline_packed_as_slice() {
    for s in inline_test_strings!() {
        let inl = Inline::new(s.as_slice());
        assert_eq!(inl.as_slice(), s.as_slice());
        assert_eq!(inl.pack().as_slice(), s.as_slice());
    }
}

#[test]
fn inline_pack_unpack() {
    let foo = Inline::new("foo");
    assert_eq!(foo.as_slice(), "foo");

    let bar = foo.pack();

    println!("{:?}", foo);
    println!("{:?}", bar);

    panic_unless!(foo == foo, "each symbol::Inline instance should be equal to itself");
    panic_unless!(bar == bar, "each symbol::Symbol instance should be equal to itself");

    panic_unless!(Unpacked::Inline(foo) == bar.unpack(),
                  "pack-unpack cycle on a symbol::Inline should yield the same symbol");
}

#[test]
fn pooled_pack_unpack() {
    let mut pool = Pool::new();
    let a_str = "it was a very nice day";
    let b_str = "and everyone was happy";

    let a = pool.symbol(a_str);
    let b = pool.symbol(b_str);
    assert_eq!(Unpacked::type_of(&a), Type::POOLED);
    assert_eq!(Unpacked::type_of(&b), Type::POOLED);

   println!("{:?} => {:?}", a, a.as_slice());
    println!("{:?}", a.unpack());

    assert_eq!(a, a);
    assert_ne!(a, b);
    assert_eq!(a.as_slice(), a_str);
    assert_eq!(b.as_slice(), b_str);
}
<commit_msg>test/test_symbol: fixes for recent Symbol API changes.<commit_after>use cripes::symbol::{Pool,Type,Unpacked,Inline,PackFormat};
use std::string::String;

macro_rules! inline_test_strings {
    () => ((0u8..16u8).map(|i| (0u8..i).map(|j| (j  + 'a' as u8) as char).collect::<String>()));
}

#[test]
fn inline_as_slice() {
    for s in inline_test_strings!() {
        let sym = Inline::new(s.as_slice());
        assert_eq!(sym.as_slice(), s.as_slice());
    }
}

#[test]
fn inline_packed_as_slice() {
    for s in inline_test_strings!() {
        let inl = Inline::new(s.as_slice());
        assert_eq!(inl.as_slice(), s.as_slice());
        assert_eq!(inl.pack().as_slice(), s.as_slice());
    }
}

#[test]
fn inline_pack_unpack() {
    let foo = Inline::new("foo");
    assert_eq!(foo.as_slice(), "foo");

    let bar = foo.pack();

    println!("{:?}", foo);
    println!("{:?}", bar);

    panic_unless!(foo == foo, "each symbol::Inline instance should be equal to itself");
    panic_unless!(bar == bar, "each symbol::Symbol instance should be equal to itself");

    panic_unless!(Unpacked::Inline(foo) == bar.unpack(),
                  "pack-unpack cycle on a symbol::Inline should yield the same symbol");
}

#[test]
fn pooled_pack_unpack() {
    let mut pool = Pool::new();
    let a_str = "it was a very nice day";
    let b_str = "and everyone was happy";

    let a = pool.symbol(a_str);
    let b = pool.symbol(b_str);
    assert_eq!(a.type_of(), Type::POOLED);
    assert_eq!(b.type_of(), Type::POOLED);

   println!("{:?} => {:?}", a, a.as_slice());
    println!("{:?}", a.unpack());

    assert_eq!(a, a);
    assert_ne!(a, b);
    assert_eq!(a.as_slice(), a_str);
    assert_eq!(b.as_slice(), b_str);
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
use itertools::Itertools;
use ra_ide_db::RootDatabase;
use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode};

use crate::{AssistContext, AssistId, Assists};

// Assist: reorder_fields
//
// Reorder the fields of record literals and record patterns in the same order as in
// the definition.
//
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = <|>Foo {bar: 0, foo: 1}
// ```
// ->
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = Foo {foo: 1, bar: 0}
// ```
//
pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    reorder::<ast::RecordLit>(acc, ctx.clone()).or_else(|| reorder::<ast::RecordPat>(acc, ctx))
}

fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let record = ctx.find_node_at_offset::<R>()?;
    let path = record.syntax().children().find_map(ast::Path::cast)?;

    let ranks = compute_fields_ranks(&path, &ctx)?;

    let fields = get_fields(&record.syntax());
    let sorted_fields = sorted_by_rank(&fields, |node| {
        *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
    });

    if sorted_fields == fields {
        return None;
    }

    let target = record.syntax().text_range();
    acc.add(AssistId("reorder_fields"), "Reorder record fields", target, |edit| {
        for (old, new) in fields.iter().zip(&sorted_fields) {
            algo::diff(old, new).into_text_edit(edit.text_edit_builder());
        }
    })
}

fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
    match node.kind() {
        RECORD_LIT => vec![RECORD_FIELD],
        RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
        _ => vec![],
    }
}

fn get_field_name(node: &SyntaxNode) -> String {
    let res = match_ast! {
        match node {
            ast::RecordField(field) => field.field_name().map(|it| it.to_string()),
            ast::RecordFieldPat(field) => field.field_name().map(|it| it.to_string()),
            _ => None,
        }
    };
    res.unwrap_or_default()
}

fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
    let kinds = get_fields_kind(record);
    record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect()
}

fn sorted_by_rank(
    fields: &[SyntaxNode],
    get_rank: impl Fn(&SyntaxNode) -> usize,
) -> Vec<SyntaxNode> {
    fields.iter().cloned().sorted_by_key(get_rank).collect()
}

fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> {
    match sema.resolve_path(path) {
        Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s),
        _ => None,
    }
}

fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<HashMap<String, usize>> {
    Some(
        struct_definition(path, &ctx.sema)?
            .fields(ctx.db)
            .iter()
            .enumerate()
            .map(|(idx, field)| (field.name(ctx.db).to_string(), idx))
            .collect(),
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_if_sorted() {
        check_assist_not_applicable(
            reorder_fields,
            r#"
        struct Foo {
            foo: i32,
            bar: i32,
        }

        const test: Foo = <|>Foo { foo: 0, bar: 0 };
        "#,
        )
    }

    #[test]
    fn trivial_empty_fields() {
        check_assist_not_applicable(
            reorder_fields,
            r#"
        struct Foo {};
        const test: Foo = <|>Foo {}
        "#,
        )
    }

    #[test]
    fn reorder_struct_fields() {
        check_assist(
            reorder_fields,
            r#"
        struct Foo {foo: i32, bar: i32};
        const test: Foo = <|>Foo {bar: 0, foo: 1}
        "#,
            r#"
        struct Foo {foo: i32, bar: i32};
        const test: Foo = Foo {foo: 1, bar: 0}
        "#,
        )
    }

    #[test]
    fn reorder_struct_pattern() {
        check_assist(
            reorder_fields,
            r#"
        struct Foo { foo: i64, bar: i64, baz: i64 }

        fn f(f: Foo) -> {
            match f {
                <|>Foo { baz: 0, ref mut bar, .. } => (),
                _ => ()
            }
        }
        "#,
            r#"
        struct Foo { foo: i64, bar: i64, baz: i64 }

        fn f(f: Foo) -> {
            match f {
                Foo { ref mut bar, baz: 0, .. } => (),
                _ => ()
            }
        }
        "#,
        )
    }

    #[test]
    fn reorder_with_extra_field() {
        check_assist(
            reorder_fields,
            r#"
            struct Foo {
                foo: String,
                bar: String,
            }

            impl Foo {
                fn new() -> Foo {
                    let foo = String::new();
                    <|>Foo {
                        bar: foo.clone(),
                        extra: "Extra field",
                        foo,
                    }
                }
            }
            "#,
            r#"
            struct Foo {
                foo: String,
                bar: String,
            }

            impl Foo {
                fn new() -> Foo {
                    let foo = String::new();
                    Foo {
                        foo,
                        bar: foo.clone(),
                        extra: "Extra field",
                    }
                }
            }
            "#,
        )
    }
}
<commit_msg>Remove unnecessary clone that prevented clippy from moving on<commit_after>use std::collections::HashMap;

use hir::{Adt, ModuleDef, PathResolution, Semantics, Struct};
use itertools::Itertools;
use ra_ide_db::RootDatabase;
use ra_syntax::{algo, ast, match_ast, AstNode, SyntaxKind, SyntaxKind::*, SyntaxNode};

use crate::{AssistContext, AssistId, Assists};

// Assist: reorder_fields
//
// Reorder the fields of record literals and record patterns in the same order as in
// the definition.
//
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = <|>Foo {bar: 0, foo: 1}
// ```
// ->
// ```
// struct Foo {foo: i32, bar: i32};
// const test: Foo = Foo {foo: 1, bar: 0}
// ```
//
pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    reorder::<ast::RecordLit>(acc, ctx).or_else(|| reorder::<ast::RecordPat>(acc, ctx))
}

fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let record = ctx.find_node_at_offset::<R>()?;
    let path = record.syntax().children().find_map(ast::Path::cast)?;

    let ranks = compute_fields_ranks(&path, &ctx)?;

    let fields = get_fields(&record.syntax());
    let sorted_fields = sorted_by_rank(&fields, |node| {
        *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())
    });

    if sorted_fields == fields {
        return None;
    }

    let target = record.syntax().text_range();
    acc.add(AssistId("reorder_fields"), "Reorder record fields", target, |edit| {
        for (old, new) in fields.iter().zip(&sorted_fields) {
            algo::diff(old, new).into_text_edit(edit.text_edit_builder());
        }
    })
}

fn get_fields_kind(node: &SyntaxNode) -> Vec<SyntaxKind> {
    match node.kind() {
        RECORD_LIT => vec![RECORD_FIELD],
        RECORD_PAT => vec![RECORD_FIELD_PAT, BIND_PAT],
        _ => vec![],
    }
}

fn get_field_name(node: &SyntaxNode) -> String {
    let res = match_ast! {
        match node {
            ast::RecordField(field) => field.field_name().map(|it| it.to_string()),
            ast::RecordFieldPat(field) => field.field_name().map(|it| it.to_string()),
            _ => None,
        }
    };
    res.unwrap_or_default()
}

fn get_fields(record: &SyntaxNode) -> Vec<SyntaxNode> {
    let kinds = get_fields_kind(record);
    record.children().flat_map(|n| n.children()).filter(|n| kinds.contains(&n.kind())).collect()
}

fn sorted_by_rank(
    fields: &[SyntaxNode],
    get_rank: impl Fn(&SyntaxNode) -> usize,
) -> Vec<SyntaxNode> {
    fields.iter().cloned().sorted_by_key(get_rank).collect()
}

fn struct_definition(path: &ast::Path, sema: &Semantics<RootDatabase>) -> Option<Struct> {
    match sema.resolve_path(path) {
        Some(PathResolution::Def(ModuleDef::Adt(Adt::Struct(s)))) => Some(s),
        _ => None,
    }
}

fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<HashMap<String, usize>> {
    Some(
        struct_definition(path, &ctx.sema)?
            .fields(ctx.db)
            .iter()
            .enumerate()
            .map(|(idx, field)| (field.name(ctx.db).to_string(), idx))
            .collect(),
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn not_applicable_if_sorted() {
        check_assist_not_applicable(
            reorder_fields,
            r#"
        struct Foo {
            foo: i32,
            bar: i32,
        }

        const test: Foo = <|>Foo { foo: 0, bar: 0 };
        "#,
        )
    }

    #[test]
    fn trivial_empty_fields() {
        check_assist_not_applicable(
            reorder_fields,
            r#"
        struct Foo {};
        const test: Foo = <|>Foo {}
        "#,
        )
    }

    #[test]
    fn reorder_struct_fields() {
        check_assist(
            reorder_fields,
            r#"
        struct Foo {foo: i32, bar: i32};
        const test: Foo = <|>Foo {bar: 0, foo: 1}
        "#,
            r#"
        struct Foo {foo: i32, bar: i32};
        const test: Foo = Foo {foo: 1, bar: 0}
        "#,
        )
    }

    #[test]
    fn reorder_struct_pattern() {
        check_assist(
            reorder_fields,
            r#"
        struct Foo { foo: i64, bar: i64, baz: i64 }

        fn f(f: Foo) -> {
            match f {
                <|>Foo { baz: 0, ref mut bar, .. } => (),
                _ => ()
            }
        }
        "#,
            r#"
        struct Foo { foo: i64, bar: i64, baz: i64 }

        fn f(f: Foo) -> {
            match f {
                Foo { ref mut bar, baz: 0, .. } => (),
                _ => ()
            }
        }
        "#,
        )
    }

    #[test]
    fn reorder_with_extra_field() {
        check_assist(
            reorder_fields,
            r#"
            struct Foo {
                foo: String,
                bar: String,
            }

            impl Foo {
                fn new() -> Foo {
                    let foo = String::new();
                    <|>Foo {
                        bar: foo.clone(),
                        extra: "Extra field",
                        foo,
                    }
                }
            }
            "#,
            r#"
            struct Foo {
                foo: String,
                bar: String,
            }

            impl Foo {
                fn new() -> Foo {
                    let foo = String::new();
                    Foo {
                        foo,
                        bar: foo.clone(),
                        extra: "Extra field",
                    }
                }
            }
            "#,
        )
    }
}
<|endoftext|>


<commit_before>use proc_macro2::TokenStream;
use quote::quote;
use syn::Field;

use super::{Request, RequestField};

impl Request {
    pub fn expand_incoming(&self, ruma_common: &TokenStream) -> TokenStream {
        let http = quote! { #ruma_common::exports::http };
        let serde = quote! { #ruma_common::exports::serde };
        let serde_json = quote! { #ruma_common::exports::serde_json };

        let error_ty = &self.error_ty;

        // FIXME: the rest of the field initializer expansions are gated `cfg(...)`
        // except this one. If we get errors about missing fields in IncomingRequest for
        // a path field look here.
        let (parse_request_path, path_vars) = if self.has_path_fields() {
            let path_vars: Vec<_> = self.path_fields().filter_map(|f| f.ident.as_ref()).collect();

            let parse_request_path = quote! {
                let (#(#path_vars,)*) = #serde::Deserialize::deserialize(
                    #serde::de::value::SeqDeserializer::<_, #serde::de::value::Error>::new(
                        path_args.iter().map(::std::convert::AsRef::as_ref)
                    )
                )?;
            };

            (parse_request_path, quote! { #(#path_vars,)* })
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let (parse_query, query_vars) = if let Some(field) = self.query_map_field() {
            let cfg_attrs =
                field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                #( #cfg_attrs )*
                let #field_name = #ruma_common::serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or(""),
                )?;
            };

            (
                parse,
                quote! {
                    #( #cfg_attrs )*
                    #field_name,
                },
            )
        } else if self.has_query_fields() {
            let (decls, names) = vars(
                self.fields.iter().filter_map(RequestField::as_query_field),
                quote! { request_query },
            );

            let request_query_ty = if self.lifetimes.query.is_empty() {
                quote! { RequestQuery }
            } else {
                quote! { IncomingRequestQuery }
            };

            let parse = quote! {
                let request_query: #request_query_ty = #ruma_common::serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or("")
                )?;

                #decls
            };

            (parse, names)
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let (parse_headers, header_vars) = if self.has_header_fields() {
            let (decls, names): (TokenStream, Vec<_>) = self
                .header_fields()
                .map(|(field, header_name)| {
                    let cfg_attrs =
                        field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();

                    let field_name = &field.ident;
                    let header_name_string = header_name.to_string();

                    let (some_case, none_case) = match &field.ty {
                        syn::Type::Path(syn::TypePath {
                            path: syn::Path { segments, .. }, ..
                        }) if segments.last().unwrap().ident == "Option" => {
                            (quote! { Some(str_value.to_owned()) }, quote! { None })
                        }
                        _ => (
                            quote! { str_value.to_owned() },
                            quote! {
                                return Err(
                                    #ruma_common::api::error::HeaderDeserializationError::MissingHeader(
                                        #header_name_string.into()
                                    ).into(),
                                )
                            },
                        ),
                    };

                    let decl = quote! {
                        #( #cfg_attrs )*
                        let #field_name = match headers.get(#header_name) {
                            Some(header_value) => {
                                let str_value = header_value.to_str()?;
                                #some_case
                            }
                            None => #none_case,
                        };
                    };

                    (
                        decl,
                        quote! {
                            #( #cfg_attrs )*
                            #field_name
                        },
                    )
                })
                .unzip();

            let parse = quote! {
                let headers = request.headers();

                #decls
            };

            (parse, quote! { #(#names,)* })
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let extract_body = self.has_body_fields().then(|| {
            let request_body_ty = if self.lifetimes.body.is_empty() {
                quote! { RequestBody }
            } else {
                quote! { IncomingRequestBody }
            };

            quote! {
                let request_body: #request_body_ty = {
                    let body = ::std::convert::AsRef::<[::std::primitive::u8]>::as_ref(
                        request.body(),
                    );

                    #serde_json::from_slice(match body {
                        // If the request body is completely empty, pretend it is an empty JSON
                        // object instead. This allows requests with only optional body parameters
                        // to be deserialized in that case.
                        [] => b"{}",
                        b => b,
                    })?
                };
            }
        });

        let (parse_body, body_vars) = if let Some(field) = self.raw_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                let #field_name =
                    ::std::convert::AsRef::<[u8]>::as_ref(request.body()).to_vec();
            };

            (parse, quote! { #field_name, })
        } else {
            vars(self.body_fields(), quote! { request_body })
        };

        quote! {
            #[automatically_derived]
            #[cfg(feature = "server")]
            impl #ruma_common::api::IncomingRequest for IncomingRequest {
                type EndpointError = #error_ty;
                type OutgoingResponse = Response;

                const METADATA: #ruma_common::api::Metadata = METADATA;

                fn try_from_http_request<B, S>(
                    request: #http::Request<B>,
                    path_args: &[S],
                ) -> ::std::result::Result<Self, #ruma_common::api::error::FromHttpRequestError>
                where
                    B: ::std::convert::AsRef<[::std::primitive::u8]>,
                    S: ::std::convert::AsRef<::std::primitive::str>,
                {
                    if request.method() != METADATA.method {
                        return Err(#ruma_common::api::error::FromHttpRequestError::MethodMismatch {
                            expected: METADATA.method,
                            received: request.method().clone(),
                        });
                    }

                    #parse_request_path
                    #parse_query
                    #parse_headers

                    #extract_body
                    #parse_body

                    ::std::result::Result::Ok(Self {
                        #path_vars
                        #query_vars
                        #header_vars
                        #body_vars
                    })
                }
            }
        }
    }
}

fn vars<'a>(
    fields: impl IntoIterator<Item = &'a Field>,
    src: TokenStream,
) -> (TokenStream, TokenStream) {
    fields
        .into_iter()
        .map(|field| {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let cfg_attrs =
                field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();

            let decl = quote! {
                #( #cfg_attrs )*
                let #field_name = #src.#field_name;
            };

            (
                decl,
                quote! {
                    #( #cfg_attrs )*
                    #field_name,
                },
            )
        })
        .unzip()
}
<commit_msg>macros: Remove unnecessary type distinction<commit_after>use proc_macro2::TokenStream;
use quote::quote;
use syn::Field;

use super::{Request, RequestField};

impl Request {
    pub fn expand_incoming(&self, ruma_common: &TokenStream) -> TokenStream {
        let http = quote! { #ruma_common::exports::http };
        let serde = quote! { #ruma_common::exports::serde };
        let serde_json = quote! { #ruma_common::exports::serde_json };

        let error_ty = &self.error_ty;

        // FIXME: the rest of the field initializer expansions are gated `cfg(...)`
        // except this one. If we get errors about missing fields in IncomingRequest for
        // a path field look here.
        let (parse_request_path, path_vars) = if self.has_path_fields() {
            let path_vars: Vec<_> = self.path_fields().filter_map(|f| f.ident.as_ref()).collect();

            let parse_request_path = quote! {
                let (#(#path_vars,)*) = #serde::Deserialize::deserialize(
                    #serde::de::value::SeqDeserializer::<_, #serde::de::value::Error>::new(
                        path_args.iter().map(::std::convert::AsRef::as_ref)
                    )
                )?;
            };

            (parse_request_path, quote! { #(#path_vars,)* })
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let (parse_query, query_vars) = if let Some(field) = self.query_map_field() {
            let cfg_attrs =
                field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                #( #cfg_attrs )*
                let #field_name = #ruma_common::serde::urlencoded::from_str(
                    &request.uri().query().unwrap_or(""),
                )?;
            };

            (
                parse,
                quote! {
                    #( #cfg_attrs )*
                    #field_name,
                },
            )
        } else if self.has_query_fields() {
            let (decls, names) = vars(
                self.fields.iter().filter_map(RequestField::as_query_field),
                quote! { request_query },
            );

            let parse = quote! {
                let request_query: IncomingRequestQuery =
                    #ruma_common::serde::urlencoded::from_str(
                        &request.uri().query().unwrap_or("")
                    )?;

                #decls
            };

            (parse, names)
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let (parse_headers, header_vars) = if self.has_header_fields() {
            let (decls, names): (TokenStream, Vec<_>) = self
                .header_fields()
                .map(|(field, header_name)| {
                    let cfg_attrs =
                        field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();

                    let field_name = &field.ident;
                    let header_name_string = header_name.to_string();

                    let (some_case, none_case) = match &field.ty {
                        syn::Type::Path(syn::TypePath {
                            path: syn::Path { segments, .. }, ..
                        }) if segments.last().unwrap().ident == "Option" => {
                            (quote! { Some(str_value.to_owned()) }, quote! { None })
                        }
                        _ => (
                            quote! { str_value.to_owned() },
                            quote! {
                                return Err(
                                    #ruma_common::api::error::HeaderDeserializationError::MissingHeader(
                                        #header_name_string.into()
                                    ).into(),
                                )
                            },
                        ),
                    };

                    let decl = quote! {
                        #( #cfg_attrs )*
                        let #field_name = match headers.get(#header_name) {
                            Some(header_value) => {
                                let str_value = header_value.to_str()?;
                                #some_case
                            }
                            None => #none_case,
                        };
                    };

                    (
                        decl,
                        quote! {
                            #( #cfg_attrs )*
                            #field_name
                        },
                    )
                })
                .unzip();

            let parse = quote! {
                let headers = request.headers();

                #decls
            };

            (parse, quote! { #(#names,)* })
        } else {
            (TokenStream::new(), TokenStream::new())
        };

        let extract_body = self.has_body_fields().then(|| {
            quote! {
                let request_body: IncomingRequestBody = {
                    let body = ::std::convert::AsRef::<[::std::primitive::u8]>::as_ref(
                        request.body(),
                    );

                    #serde_json::from_slice(match body {
                        // If the request body is completely empty, pretend it is an empty JSON
                        // object instead. This allows requests with only optional body parameters
                        // to be deserialized in that case.
                        [] => b"{}",
                        b => b,
                    })?
                };
            }
        });

        let (parse_body, body_vars) = if let Some(field) = self.raw_body_field() {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let parse = quote! {
                let #field_name =
                    ::std::convert::AsRef::<[u8]>::as_ref(request.body()).to_vec();
            };

            (parse, quote! { #field_name, })
        } else {
            vars(self.body_fields(), quote! { request_body })
        };

        quote! {
            #[automatically_derived]
            #[cfg(feature = "server")]
            impl #ruma_common::api::IncomingRequest for IncomingRequest {
                type EndpointError = #error_ty;
                type OutgoingResponse = Response;

                const METADATA: #ruma_common::api::Metadata = METADATA;

                fn try_from_http_request<B, S>(
                    request: #http::Request<B>,
                    path_args: &[S],
                ) -> ::std::result::Result<Self, #ruma_common::api::error::FromHttpRequestError>
                where
                    B: ::std::convert::AsRef<[::std::primitive::u8]>,
                    S: ::std::convert::AsRef<::std::primitive::str>,
                {
                    if request.method() != METADATA.method {
                        return Err(#ruma_common::api::error::FromHttpRequestError::MethodMismatch {
                            expected: METADATA.method,
                            received: request.method().clone(),
                        });
                    }

                    #parse_request_path
                    #parse_query
                    #parse_headers

                    #extract_body
                    #parse_body

                    ::std::result::Result::Ok(Self {
                        #path_vars
                        #query_vars
                        #header_vars
                        #body_vars
                    })
                }
            }
        }
    }
}

fn vars<'a>(
    fields: impl IntoIterator<Item = &'a Field>,
    src: TokenStream,
) -> (TokenStream, TokenStream) {
    fields
        .into_iter()
        .map(|field| {
            let field_name = field.ident.as_ref().expect("expected field to have an identifier");
            let cfg_attrs =
                field.attrs.iter().filter(|a| a.path.is_ident("cfg")).collect::<Vec<_>>();

            let decl = quote! {
                #( #cfg_attrs )*
                let #field_name = #src.#field_name;
            };

            (
                decl,
                quote! {
                    #( #cfg_attrs )*
                    #field_name,
                },
            )
        })
        .unzip()
}
<|endoftext|>