<commit_before>use parser::Identifier;
use operations::{Operation};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, ScopeItem, TypeId};

pub fn define_boolean(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let bool_type = scope.declare_type(
        Identifier::from("bool"),
        ItemType::Primitive(1)
    );
    scope.register_primitive("bool", bool_type);

    scope.declare_constant(
        Identifier::from("true"),
        bool_type,
        vec![1u8]
    );

    scope.declare_constant(
        Identifier::from("false"),
        bool_type,
        vec![0u8]
    );

    let unit_type = scope.primitives().unit();

    scope.declare_builtin_function(
        // Special method for displaying this primitive (used from print/println)
        // This name is such that it could never be called directly
        // from the language itself
        Identifier::from("std::fmt::Display::print"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(bool_type)],
            return_type: unit_type,
        },
        move |scope, args, _| {
            match args[0] {
                ScopeItem::TypedBlock {memory, ..} => Ok(vec![
                    Operation::Increment {
                        target: memory.position(),
                        amount: b'0',
                    },
                    Operation::Write {
                        target: memory,
                    },
                    // Need to make sure we reverse the operation after so this function has no
                    // side effects
                    Operation::Decrement {
                        target: memory.position(),
                        amount: b'0',
                    },
                ]),
                ScopeItem::Constant {type_id, ref bytes} => {
                    let bool_type = scope.primitives().bool();
                    debug_assert_eq!(type_id, bool_type);

                    let u8_type = scope.primitives().u8();
                    let mem = scope.allocate(u8_type);

                    // This code assumes that this is 1
                    debug_assert_eq!(bytes.len(), 1);
                    let value = b'0' + bytes[0];
                    Ok(vec![Operation::TempAllocate {
                        temp: mem,
                        body: vec![
                            Operation::Increment {
                                target: mem.position(),
                                amount: value,
                            },
                            Operation::Write {
                                target: mem,
                            },
                            Operation::Decrement {
                                target: mem.position(),
                                amount: value,
                            },
                        ],
                        should_zero: false,
                    }])
                },
                _ => unreachable!(),
            }
        }
    );

    scope.declare_builtin_function(
        Identifier::from("std::ops::Not"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(bool_type)],
            return_type: bool_type,
        },
        move |scope, args, target| {
            let bool_type = scope.primitives().bool();
            match args[0] {
                ScopeItem::TypedBlock {memory, ..} => {
                    let temp0 = scope.allocate(bool_type);
                    Ok(vec![Operation::TempAllocate {
                        temp: temp0,
                        body: vec![
                            // Need to copy to the destination because the algorithm consumes
                            // the operand
                            // After this copy the operand becomes `target` (x in the algorithm)
                            Operation::Copy {
                                source: memory.position(),
                                target: target.position(),
                                size: target.size(),
                            },

                            // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#x_.3D_not_x_.28boolean.2C_logical.29
                            //
                            // temp0[-]+
                            // x[-temp0-]temp0[x+temp0-]
                            //
                            // Results in x = !x and temp0 = 0
                            Operation::Increment {
                                target: temp0.position(),
                                amount: 1,
                            },
                            Operation::Loop {
                                cond: target.position(),
                                body: vec![
                                    Operation::Decrement {
                                        target: target.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: temp0.position(),
                                        amount: 1,
                                    },
                                ],
                            },
                            Operation::Loop {
                                cond: temp0.position(),
                                body: vec![
                                    Operation::Increment {
                                        target: target.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: temp0.position(),
                                        amount: 1,
                                    },
                                ],
                            },
                        ],
                        should_zero: false,
                    }])
                },
                ScopeItem::Constant {type_id, ref bytes} => {
                    debug_assert_eq!(type_id, bool_type);
                    // This code assumes that this is 1
                    debug_assert_eq!(bytes.len(), 1);

                    Ok(match bytes[0] {
                        //TODO: Verify if this makes sense or if we should explicitly zero
                        1 => Vec::new(),
                        0 => vec![
                            Operation::Increment {
                                target: target.position(),
                                amount: 1,
                            },
                        ],
                        _ => unreachable!(),
                    })
                },
                _ => unreachable!(),
            }
        }
    );

    // boolean and operator (operator&&) and boolean or operator (operator||)
    // These operations have special names because they are not regular functions
    // that can be defined or overloaded
    // The reason these are not definable is because they have to support short
    // circuiting. This behaviour cannot be modelled by a trait, so these special
    // operators are not definable by the user.
    scope.declare_builtin_function(
        Identifier::from("operator||"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(bool_type), FuncArgType::Arg(bool_type)],
            return_type: bool_type,
        },
        move |scope, args, target| {
            let bool_type = scope.primitives().bool();

            Ok(match (&args[0], &args[1]) {
                (&ScopeItem::Constant {type_id: xt, bytes: ref xb}, &ScopeItem::Constant {type_id: yt, bytes: ref yb}) => {
                    debug_assert_eq!(xt, bool_type);
                    debug_assert_eq!(yt, bool_type);
                    // This code assumes that this is 1
                    debug_assert_eq!(xb.len(), 1);
                    debug_assert_eq!(yb.len(), 1);

                    // The `> 0` converts the byte-representation into a Rust boolean
                    let x = xb[0] > 0;
                    let y = yb[0] > 0;

                    match x || y {
                        false => Vec::new(),
                        true => vec![Operation::Increment {
                            target: target.position(),
                            amount: 1,
                        }],
                    }
                },
                /// Thanks to certain properties of booleans, we can evaluate certain things during
                /// compilation and avoid a lot of extra computation.
                (&ScopeItem::Constant {type_id: const_type, ref bytes}, &ScopeItem::TypedBlock {type_id: other_type, memory}) |
                (&ScopeItem::TypedBlock {type_id: other_type, memory}, &ScopeItem::Constant {type_id: const_type, ref bytes}) => {
                    debug_assert_eq!(const_type, bool_type);
                    debug_assert_eq!(other_type, bool_type);
                    // This code assumes that this is 1
                    debug_assert_eq!(bytes.len(), 1);

                    match bytes[0] {
                        // If either operand is true, the || operator always returns true
                        1 => vec![Operation::Increment {
                            target: target.position(),
                            amount: 1,
                        }],
                        // If either operand is false, the || operator always returns its other operand
                        0 => vec![Operation::Copy {
                            source: memory.position(),
                            target: target.position(),
                            size: memory.size(),
                        }],
                        _ => unreachable!(),
                    }
                },
                (&ScopeItem::TypedBlock {memory: x, ..}, &ScopeItem::TypedBlock {memory: y, ..}) => {
                    let temp0 = scope.allocate(bool_type);
                    vec![Operation::TempAllocate {
                        temp: temp0,
                        body: vec![
                            // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#z_.3D_x_or_y_.28boolean.2C_logical.29
                            //
                            // z[-]
                            // temp0[-]+
                            // x[z+temp0-x-]
                            // temp0[-
                            //  y[z+y-]
                            // ]
                            // y[-]
                            Operation::Increment {
                                target: temp0.position(),
                                amount: 1,
                            },
                            Operation::Loop {
                                cond: x.position(),
                                body: vec![
                                    Operation::Increment {
                                        target: target.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: temp0.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: x.position(),
                                        amount: 1,
                                    },
                                ],
                            },
                            Operation::Loop {
                                cond: temp0.position(),
                                body: vec![
                                    Operation::Decrement {
                                        target: temp0.position(),
                                        amount: 1,
                                    },
                                    Operation::Loop {
                                        cond: y.position(),
                                        body: vec![
                                            Operation::Increment {
                                                target: target.position(),
                                                amount: 1,
                                            },
                                            Operation::Decrement {
                                                target: y.position(),
                                                amount: 1,
                                            },
                                        ],
                                    },
                                ],
                            },
                            Operation::Zero {
                                target: y,
                            }
                        ],
                        should_zero: false,
                    }]
                },
                _ => unreachable!(),
            })
        }
    );

    bool_type
}

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

    use parser::Identifier;
    use operations::scope::{ScopeType, ScopeItem};

    #[test]
    fn defines_primitive() {
        let mut scope = ScopeStack::new();
        define_boolean(&mut scope);

        let bool_type_id = match **scope.lookup_type(&Identifier::from("bool")).first().unwrap() {
            ScopeType::Type(id) => id,
        };
        assert_eq!(scope.primitives().bool(), bool_type_id);
    }

    #[test]
    fn constants() {
        let mut scope = ScopeStack::new();
        define_boolean(&mut scope);

        let bool_type_id = match **scope.lookup_type(&Identifier::from("bool")).first().unwrap() {
            ScopeType::Type(id) => id,
        };

        let true_bytes = match **scope.lookup(&Identifier::from("true")).first().unwrap() {
            ScopeItem::Constant {type_id, ref bytes} => {
                assert_eq!(type_id, bool_type_id);
                assert_eq!(*bytes, vec![1]);
                bytes
            },
            _ => unreachable!(),
        };

        let false_bytes = match **scope.lookup(&Identifier::from("false")).first().unwrap() {
            ScopeItem::Constant {type_id, ref bytes} => {
                assert_eq!(type_id, bool_type_id);
                assert_eq!(*bytes, vec![0]);
                bytes
            },
            _ => unreachable!(),
        };

        // No matter what the value of both, this property must always hold
        assert!(true_bytes != false_bytes);
    }
}
<commit_msg>Implemented && operator<commit_after>use parser::Identifier;
use operations::{Operation};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, ScopeItem, TypeId};

pub fn define_boolean(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let bool_type = scope.declare_type(
        Identifier::from("bool"),
        ItemType::Primitive(1)
    );
    scope.register_primitive("bool", bool_type);

    scope.declare_constant(
        Identifier::from("true"),
        bool_type,
        vec![1u8]
    );

    scope.declare_constant(
        Identifier::from("false"),
        bool_type,
        vec![0u8]
    );

    let unit_type = scope.primitives().unit();

    scope.declare_builtin_function(
        // Special method for displaying this primitive (used from print/println)
        // This name is such that it could never be called directly
        // from the language itself
        Identifier::from("std::fmt::Display::print"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(bool_type)],
            return_type: unit_type,
        },
        move |scope, args, _| {
            match args[0] {
                ScopeItem::TypedBlock {memory, ..} => Ok(vec![
                    Operation::Increment {
                        target: memory.position(),
                        amount: b'0',
                    },
                    Operation::Write {
                        target: memory,
                    },
                    // Need to make sure we reverse the operation after so this function has no
                    // side effects
                    Operation::Decrement {
                        target: memory.position(),
                        amount: b'0',
                    },
                ]),
                ScopeItem::Constant {type_id, ref bytes} => {
                    let bool_type = scope.primitives().bool();
                    debug_assert_eq!(type_id, bool_type);

                    let u8_type = scope.primitives().u8();
                    let mem = scope.allocate(u8_type);

                    // This code assumes that this is 1
                    debug_assert_eq!(bytes.len(), 1);
                    let value = b'0' + bytes[0];
                    Ok(vec![Operation::TempAllocate {
                        temp: mem,
                        body: vec![
                            Operation::Increment {
                                target: mem.position(),
                                amount: value,
                            },
                            Operation::Write {
                                target: mem,
                            },
                            Operation::Decrement {
                                target: mem.position(),
                                amount: value,
                            },
                        ],
                        should_zero: false,
                    }])
                },
                _ => unreachable!(),
            }
        }
    );

    scope.declare_builtin_function(
        Identifier::from("std::ops::Not"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(bool_type)],
            return_type: bool_type,
        },
        move |scope, args, target| {
            let bool_type = scope.primitives().bool();
            match args[0] {
                ScopeItem::TypedBlock {memory, ..} => {
                    let temp0 = scope.allocate(bool_type);
                    Ok(vec![Operation::TempAllocate {
                        temp: temp0,
                        body: vec![
                            // Need to copy to the destination because the algorithm consumes
                            // the operand
                            // After this copy the operand becomes `target` (x in the algorithm)
                            Operation::Copy {
                                source: memory.position(),
                                target: target.position(),
                                size: target.size(),
                            },

                            // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#x_.3D_not_x_.28boolean.2C_logical.29
                            //
                            // temp0[-]+
                            // x[-temp0-]temp0[x+temp0-]
                            //
                            // Results in x = !x and temp0 = 0
                            Operation::Increment {
                                target: temp0.position(),
                                amount: 1,
                            },
                            Operation::Loop {
                                cond: target.position(),
                                body: vec![
                                    Operation::Decrement {
                                        target: target.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: temp0.position(),
                                        amount: 1,
                                    },
                                ],
                            },
                            Operation::Loop {
                                cond: temp0.position(),
                                body: vec![
                                    Operation::Increment {
                                        target: target.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: temp0.position(),
                                        amount: 1,
                                    },
                                ],
                            },
                        ],
                        should_zero: false,
                    }])
                },
                ScopeItem::Constant {type_id, ref bytes} => {
                    debug_assert_eq!(type_id, bool_type);
                    // This code assumes that this is 1
                    debug_assert_eq!(bytes.len(), 1);

                    Ok(match bytes[0] {
                        //TODO: Verify if this makes sense or if we should explicitly zero
                        1 => Vec::new(),
                        0 => vec![
                            Operation::Increment {
                                target: target.position(),
                                amount: 1,
                            },
                        ],
                        _ => unreachable!(),
                    })
                },
                _ => unreachable!(),
            }
        }
    );

    // boolean and operator (operator&&) and boolean or operator (operator||)
    // These operations have special names because they are not regular functions
    // that can be defined or overloaded
    // The reason these are not definable is because they have to support short
    // circuiting. This behaviour cannot be modelled by a trait, so these special
    // operators are not definable by the user.
    scope.declare_builtin_function(
        Identifier::from("operator||"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(bool_type), FuncArgType::Arg(bool_type)],
            return_type: bool_type,
        },
        move |scope, args, target| {
            let bool_type = scope.primitives().bool();

            Ok(match (&args[0], &args[1]) {
                (&ScopeItem::Constant {type_id: xt, bytes: ref xb}, &ScopeItem::Constant {type_id: yt, bytes: ref yb}) => {
                    debug_assert_eq!(xt, bool_type);
                    debug_assert_eq!(yt, bool_type);
                    // This code assumes that this is 1
                    debug_assert_eq!(xb.len(), 1);
                    debug_assert_eq!(yb.len(), 1);

                    // The `> 0` converts the byte-representation into a Rust boolean
                    let x = xb[0] > 0;
                    let y = yb[0] > 0;

                    match x || y {
                        false => Vec::new(),
                        true => vec![Operation::Increment {
                            target: target.position(),
                            amount: 1,
                        }],
                    }
                },
                /// Thanks to certain properties of booleans, we can evaluate certain things during
                /// compilation and avoid a lot of extra computation.
                (&ScopeItem::Constant {type_id: const_type, ref bytes}, &ScopeItem::TypedBlock {type_id: other_type, memory}) |
                (&ScopeItem::TypedBlock {type_id: other_type, memory}, &ScopeItem::Constant {type_id: const_type, ref bytes}) => {
                    debug_assert_eq!(const_type, bool_type);
                    debug_assert_eq!(other_type, bool_type);
                    // This code assumes that this is 1
                    debug_assert_eq!(bytes.len(), 1);

                    match bytes[0] {
                        // If either operand is true, the || operator always returns true
                        1 => vec![Operation::Increment {
                            target: target.position(),
                            amount: 1,
                        }],
                        // If either operand is false, the || operator always returns its other operand
                        0 => vec![Operation::Copy {
                            source: memory.position(),
                            target: target.position(),
                            size: memory.size(),
                        }],
                        _ => unreachable!(),
                    }
                },
                (&ScopeItem::TypedBlock {memory: x, ..}, &ScopeItem::TypedBlock {memory: y, ..}) => {
                    let temp0 = scope.allocate(bool_type);
                    vec![Operation::TempAllocate {
                        temp: temp0,
                        body: vec![
                            // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#z_.3D_x_or_y_.28boolean.2C_logical.29
                            //
                            // z[-]
                            // temp0[-]+
                            // x[z+temp0-x-]
                            // temp0[-
                            //  y[z+y-]
                            // ]
                            // y[-]
                            Operation::Increment {
                                target: temp0.position(),
                                amount: 1,
                            },
                            Operation::Loop {
                                cond: x.position(),
                                body: vec![
                                    Operation::Increment {
                                        target: target.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: temp0.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: x.position(),
                                        amount: 1,
                                    },
                                ],
                            },
                            Operation::Loop {
                                cond: temp0.position(),
                                body: vec![
                                    Operation::Decrement {
                                        target: temp0.position(),
                                        amount: 1,
                                    },
                                    Operation::Loop {
                                        cond: y.position(),
                                        body: vec![
                                            Operation::Increment {
                                                target: target.position(),
                                                amount: 1,
                                            },
                                            Operation::Decrement {
                                                target: y.position(),
                                                amount: 1,
                                            },
                                        ],
                                    },
                                ],
                            },
                            Operation::Zero {
                                target: y,
                            }
                        ],
                        should_zero: false,
                    }]
                },
                _ => unreachable!(),
            })
        }
    );

    scope.declare_builtin_function(
        Identifier::from("operator&&"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(bool_type), FuncArgType::Arg(bool_type)],
            return_type: bool_type,
        },
        move |scope, args, target| {
            let bool_type = scope.primitives().bool();

            Ok(match (&args[0], &args[1]) {
                (&ScopeItem::Constant {type_id: xt, bytes: ref xb}, &ScopeItem::Constant {type_id: yt, bytes: ref yb}) => {
                    debug_assert_eq!(xt, bool_type);
                    debug_assert_eq!(yt, bool_type);
                    // This code assumes that this is 1
                    debug_assert_eq!(xb.len(), 1);
                    debug_assert_eq!(yb.len(), 1);

                    // The `> 0` converts the byte-representation into a Rust boolean
                    let x = xb[0] > 0;
                    let y = yb[0] > 0;

                    match x && y {
                        false => Vec::new(),
                        true => vec![Operation::Increment {
                            target: target.position(),
                            amount: 1,
                        }],
                    }
                },
                /// Thanks to certain properties of booleans, we can evaluate certain things during
                /// compilation and avoid a lot of extra computation.
                (&ScopeItem::Constant {type_id: const_type, ref bytes}, &ScopeItem::TypedBlock {type_id: other_type, memory}) |
                (&ScopeItem::TypedBlock {type_id: other_type, memory}, &ScopeItem::Constant {type_id: const_type, ref bytes}) => {
                    debug_assert_eq!(const_type, bool_type);
                    debug_assert_eq!(other_type, bool_type);
                    // This code assumes that this is 1
                    debug_assert_eq!(bytes.len(), 1);

                    match bytes[0] {
                        // If either operand is false, the && operator always returns false
                        0 => Vec::new(),
                        // If either operand is true, the && operator always returns its other operand
                        1 => vec![Operation::Copy {
                            source: memory.position(),
                            target: target.position(),
                            size: memory.size(),
                        }],
                        _ => unreachable!(),
                    }
                },
                (&ScopeItem::TypedBlock {memory: x, ..}, &ScopeItem::TypedBlock {memory: y, ..}) => vec![
                    // Algorithm from: https://esolangs.org/wiki/Brainfuck_algorithms#z_.3D_x_and_y_.28boolean.2C_logical.29
                    //
                    // z[-]
                    // x[
                    //  y[z+y-]
                    //  x-
                    // ]
                    // y[-]
                    Operation::Loop {
                        cond: x.position(),
                        body: vec![
                            Operation::Loop {
                                cond: y.position(),
                                body: vec![
                                    Operation::Increment {
                                        target: target.position(),
                                        amount: 1,
                                    },
                                    Operation::Decrement {
                                        target: y.position(),
                                        amount: 1,
                                    },
                                ],
                            },
                            Operation::Decrement {
                                target: x.position(),
                                amount: 1,
                            },
                        ],
                    },
                    Operation::Zero {
                        target: y,
                    },
                ],
                _ => unreachable!(),
            })
        }
    );

    bool_type
}

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

    use parser::Identifier;
    use operations::scope::{ScopeType, ScopeItem};

    #[test]
    fn defines_primitive() {
        let mut scope = ScopeStack::new();
        define_boolean(&mut scope);

        let bool_type_id = match **scope.lookup_type(&Identifier::from("bool")).first().unwrap() {
            ScopeType::Type(id) => id,
        };
        assert_eq!(scope.primitives().bool(), bool_type_id);
    }

    #[test]
    fn constants() {
        let mut scope = ScopeStack::new();
        define_boolean(&mut scope);

        let bool_type_id = match **scope.lookup_type(&Identifier::from("bool")).first().unwrap() {
            ScopeType::Type(id) => id,
        };

        let true_bytes = match **scope.lookup(&Identifier::from("true")).first().unwrap() {
            ScopeItem::Constant {type_id, ref bytes} => {
                assert_eq!(type_id, bool_type_id);
                assert_eq!(*bytes, vec![1]);
                bytes
            },
            _ => unreachable!(),
        };

        let false_bytes = match **scope.lookup(&Identifier::from("false")).first().unwrap() {
            ScopeItem::Constant {type_id, ref bytes} => {
                assert_eq!(type_id, bool_type_id);
                assert_eq!(*bytes, vec![0]);
                bytes
            },
            _ => unreachable!(),
        };

        // No matter what the value of both, this property must always hold
        assert!(true_bytes != false_bytes);
    }
}
<|endoftext|>


<commit_before>
use std::iter;
use std::io::{Write};
use std::io;

use encoding::types::{EncodingRef, EncoderTrap};
use encoding::all::{UTF_8};
use byteorder::{LittleEndian, WriteBytesExt};

use consts;
use img::{Image};

pub struct Printer<W: io::Write> {
    writer: io::BufWriter<W>,
    codec: EncodingRef,
    trap: EncoderTrap
}

impl<W: io::Write> Printer<W> {
    pub fn new(writer: W,
               codec: Option<EncodingRef>,
               trap: Option<EncoderTrap>) -> Printer<W> {
        Printer{
            writer: io::BufWriter::new(writer),
            codec: codec.unwrap_or(UTF_8 as EncodingRef),
            trap: trap.unwrap_or(EncoderTrap::Replace)
        }
    }

    fn encode(&mut self, content: &str) -> Vec<u8> {
        self.codec.encode(content, self.trap).unwrap()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.writer.write(buf)
    }

    fn write_u8(&mut self, n: u8) -> io::Result<usize> {
        self.write(vec!(n).as_slice())
    }

    fn write_u16le(&mut self, n: u16) -> io::Result<usize> {
        let mut wtr = vec![];
        wtr.write_u16::<LittleEndian>(n).unwrap();
        self.write(wtr.as_slice())
    }

    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }

    pub fn hwinit(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_INIT);
        self
    }

    pub fn hwselect(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_SELECT);
        self
    }

    pub fn hwreset(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_RESET);
        self
    }

    pub fn print(&mut self, content: &str) -> &mut Printer<W> {
        // let rv = self.encode(content);
        let rv = self.encode(content);
        let _ = self.write(rv.as_slice());
        self
    }

    pub fn println(&mut self, content: &str) -> &mut Printer<W> {
        self.print(format!("{}{}", content, consts::EOL).as_ref());
        self
    }

    pub fn text(&mut self, content: &str) -> &mut Printer<W> {
        self.println(content);
        self
    }

    pub fn line_space(&mut self, n: i32) -> &mut Printer<W> {
        if n >= 0 {
            let _ = self.write(consts::LS_SET);
            let _ = self.write_u8(n as u8);
        } else {
            let _ = self.write(consts::LS_DEFAULT);
        }
        self
    }

    pub fn feed(&mut self, n: usize) -> &mut Printer<W> {
        let n = if n < 1 { 1 } else { n };
        let _ = self.write(iter::repeat(consts::EOL)
                           .take(n)
                           .collect::<String>()
                           .as_ref());
        self
    }

    pub fn control(&mut self, ctrl: &str) -> &mut Printer<W> {
        let ctrl_upper = ctrl.to_uppercase();
        let ctrl_value = match ctrl_upper.as_ref() {
            "LF" => consts::CTL_LF,
            "FF" => consts::CTL_FF,
            "CR" => consts::CTL_CR,
            "HT" => consts::CTL_HT,
            "VT" => consts::CTL_VT,
            _ => panic!("Invalid control action: {}", ctrl)
        };
        let _ = self.write(ctrl_value);
        self
    }

    pub fn align(&mut self, alignment: &str) -> &mut Printer<W> {
        let align_upper = alignment.to_uppercase();
        let align_value = match align_upper.as_ref() {
            "LT" => consts::TXT_ALIGN_LT,
            "CT" => consts::TXT_ALIGN_CT,
            "RT" => consts::TXT_ALIGN_RT,
            _ => panic!("Invalid alignment: {}", alignment)
        };
        let _ = self.write(align_value);
        self
    }

    pub fn font(&mut self, family: &str) -> &mut Printer<W> {
        let family_upper = family.to_uppercase();
        let family_value = match family_upper.as_ref() {
            "A" => consts::TXT_FONT_A,
            "B" => consts::TXT_FONT_B,
            "C" => consts::TXT_FONT_C,
            _ => panic!("Invalid font family: {}", family)
        };
        let _ = self.write(family_value);
        self
    }

    pub fn style(&mut self, kind: &str) -> &mut Printer<W> {
        let kind_upper = kind.to_lowercase();
        match kind_upper.as_ref() {
            "B" => {
                let _ = self.write(consts::TXT_UNDERL_OFF);
                let _ = self.write(consts::TXT_BOLD_ON);
            }
            "U" => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL_ON);
            }
            "U2" => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL2_ON);
            }
            "BU" => {
                let _ = self.write(consts::TXT_BOLD_ON);
                let _ = self.write(consts::TXT_UNDERL_ON);
            }
            "BU2" => {
                let _ = self.write(consts::TXT_BOLD_ON);
                let _ = self.write(consts::TXT_UNDERL2_ON);
            }
            "NORMAL" | _ => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL_OFF);
            }
        }
        self
    }

    pub fn size(&mut self, width: usize, height: usize) -> &mut Printer<W> {
        let _ = self.write(consts::TXT_NORMAL);
        if width == 2 {
            let _ = self.write(consts::TXT_2WIDTH);
        }
        if height == 2 {
            let _ = self.write(consts::TXT_2HEIGHT);
        }
        self
    }

    pub fn hardware(&mut self, hw: &str) -> &mut Printer<W> {
        let value = match hw {
            "INIT" => consts::HW_INIT,
            "SELECT" => consts::HW_SELECT,
            "RESET" => consts::HW_RESET,
            _ => panic!("Invalid hardware command: {}", hw)
        };
        let _ = self.write(value);
        self
    }

    pub fn barcode(&mut self,
                   code: &str,
                   kind: &str,
                   position: &str,
                   font: &str,
                   width: usize, height: usize) -> &mut Printer<W> {
        if width >= 1 || width <= 255 {
            let _ = self.write(consts::BARCODE_WIDTH);
        }
        if height >= 2 || height <= 6 {
            let _ = self.write(consts::BARCODE_HEIGHT);
        }

        let font = font.to_uppercase();
        let position = position.to_uppercase();
        let kind = kind.to_uppercase().replace("-", "_");
        let font_value = match font.as_ref() {
            "B" => consts::BARCODE_FONT_B,
            "A" | _ => consts::BARCODE_FONT_A
        };
        let txt_value = match position.as_ref() {
            "OFF" => consts::BARCODE_TXT_OFF,
            "ABV" => consts::BARCODE_TXT_ABV,
            "BTH" => consts::BARCODE_TXT_BTH,
            "BLW" | _ => consts::BARCODE_TXT_BLW,
        };
        let kind_value = match kind.as_ref() {
            "UPC_A"  => consts::BARCODE_UPC_A,
            "UPC_E"  => consts::BARCODE_UPC_E,
            "EAN8"   => consts::BARCODE_EAN8,
            "CODE39" => consts::BARCODE_CODE39,
            "ITF"    => consts::BARCODE_ITF,
            "NW7"    => consts::BARCODE_NW7,
            "EAN13" | _ => consts::BARCODE_EAN13
        };
        let _ = self.write(font_value);
        let _ = self.write(txt_value);
        let _ = self.write(kind_value);
        let _ = self.write(code.as_bytes());
        self
    }

    pub fn qrimage(&mut self) -> &mut Printer<W> {
        self
    }

    pub fn qrcode(&mut self,
                  code: &str,
                  version: Option<i32>,
                  level: &str,
                  size: Option<i32>) -> &mut Printer<W> {
        let level = level.to_uppercase();
        let level_value = match level.as_ref() {
            "M" => consts::QR_LEVEL_M,
            "Q" => consts::QR_LEVEL_Q,
            "H" => consts::QR_LEVEL_H,
            "L" | _ => consts::QR_LEVEL_L,
        };
        let _ = self.write(consts::TYPE_QR);
        let _ = self.write(consts::CODE2D);
        let _ = self.write_u8(version.unwrap_or(3) as u8);
        let _ = self.write(level_value);
        let _ = self.write_u8(size.unwrap_or(3) as u8);
        let _ = self.write_u16le(code.len() as u16);
        let _ = self.write(code.as_bytes());
        self
    }

    pub fn cashdraw(&mut self, pin: i32) -> &mut Printer<W> {
        let pin_value = if pin == 5 {
            consts::CD_KICK_5
        } else {
            consts::CD_KICK_2
        };
        let _ = self.write(pin_value);
        self
    }

    pub fn cut(&mut self, part: bool) -> &mut Printer<W> {
        self.print(iter::repeat(consts::EOL)
                   .take(3)
                   .collect::<String>()
                   .as_ref());
        let paper_cut_type = if part {
            consts::PAPER_PART_CUT
        } else {
            consts::PAPER_FULL_CUT
        };
        let _ = self.write(paper_cut_type);
        self
    }

    pub fn bit_image(&mut self,
                    image: &Image,
                    density: Option<&str>) -> &mut Printer<W> {
        let density = density.unwrap_or("d24");
        let density_upper = density.to_uppercase();
        let header = match density_upper.as_ref() {
            "S8"  => consts::BITMAP_S8,
            "D8"  => consts::BITMAP_D8,
            "S24" => consts::BITMAP_S24,
            "D24" | _ => consts::BITMAP_D24,
        };
        let n = if density == "s8" || density == "d8" { 1 } else { 3 };
        self.line_space(0);
        for line in image.bitimage_lines(n*8) {
            let _ = self.write(header);
            let _ = self.write_u16le((line.len() / n as usize) as u16);
            let _ = self.write(line.as_ref());
            self.feed(1);
        }
        self
    }

    pub fn raster(&mut self, image: &Image, mode: Option<&str>) -> &mut Printer<W> {
        let mode_upper = mode.unwrap_or("NORMAL").to_uppercase();
        let header = match mode_upper.as_ref() {
            "DH" => consts::GSV0_DH,
            "DWDH" => consts::GSV0_DWDH,
            "DW" | "NORMAL" | _ => consts::GSV0_DW,
        };
        let _ = self.write(header);
        let _ = self.write_u16le(image.width as u16);
        let _ = self.write_u16le(image.height as u16);
        let _ = self.write(image.get_raster().as_ref());
        self
    }
}
<commit_msg>Fixes typo that prevents the style from changing<commit_after>
use std::iter;
use std::io::{Write};
use std::io;

use encoding::types::{EncodingRef, EncoderTrap};
use encoding::all::{UTF_8};
use byteorder::{LittleEndian, WriteBytesExt};

use consts;
use img::{Image};

pub struct Printer<W: io::Write> {
    writer: io::BufWriter<W>,
    codec: EncodingRef,
    trap: EncoderTrap
}

impl<W: io::Write> Printer<W> {
    pub fn new(writer: W,
               codec: Option<EncodingRef>,
               trap: Option<EncoderTrap>) -> Printer<W> {
        Printer{
            writer: io::BufWriter::new(writer),
            codec: codec.unwrap_or(UTF_8 as EncodingRef),
            trap: trap.unwrap_or(EncoderTrap::Replace)
        }
    }

    fn encode(&mut self, content: &str) -> Vec<u8> {
        self.codec.encode(content, self.trap).unwrap()
    }

    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.writer.write(buf)
    }

    fn write_u8(&mut self, n: u8) -> io::Result<usize> {
        self.write(vec!(n).as_slice())
    }

    fn write_u16le(&mut self, n: u16) -> io::Result<usize> {
        let mut wtr = vec![];
        wtr.write_u16::<LittleEndian>(n).unwrap();
        self.write(wtr.as_slice())
    }

    pub fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }

    pub fn hwinit(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_INIT);
        self
    }

    pub fn hwselect(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_SELECT);
        self
    }

    pub fn hwreset(&mut self) -> &mut Printer<W> {
        let _ = self.write(consts::HW_RESET);
        self
    }

    pub fn print(&mut self, content: &str) -> &mut Printer<W> {
        // let rv = self.encode(content);
        let rv = self.encode(content);
        let _ = self.write(rv.as_slice());
        self
    }

    pub fn println(&mut self, content: &str) -> &mut Printer<W> {
        self.print(format!("{}{}", content, consts::EOL).as_ref());
        self
    }

    pub fn text(&mut self, content: &str) -> &mut Printer<W> {
        self.println(content);
        self
    }

    pub fn line_space(&mut self, n: i32) -> &mut Printer<W> {
        if n >= 0 {
            let _ = self.write(consts::LS_SET);
            let _ = self.write_u8(n as u8);
        } else {
            let _ = self.write(consts::LS_DEFAULT);
        }
        self
    }

    pub fn feed(&mut self, n: usize) -> &mut Printer<W> {
        let n = if n < 1 { 1 } else { n };
        let _ = self.write(iter::repeat(consts::EOL)
                           .take(n)
                           .collect::<String>()
                           .as_ref());
        self
    }

    pub fn control(&mut self, ctrl: &str) -> &mut Printer<W> {
        let ctrl_upper = ctrl.to_uppercase();
        let ctrl_value = match ctrl_upper.as_ref() {
            "LF" => consts::CTL_LF,
            "FF" => consts::CTL_FF,
            "CR" => consts::CTL_CR,
            "HT" => consts::CTL_HT,
            "VT" => consts::CTL_VT,
            _ => panic!("Invalid control action: {}", ctrl)
        };
        let _ = self.write(ctrl_value);
        self
    }

    pub fn align(&mut self, alignment: &str) -> &mut Printer<W> {
        let align_upper = alignment.to_uppercase();
        let align_value = match align_upper.as_ref() {
            "LT" => consts::TXT_ALIGN_LT,
            "CT" => consts::TXT_ALIGN_CT,
            "RT" => consts::TXT_ALIGN_RT,
            _ => panic!("Invalid alignment: {}", alignment)
        };
        let _ = self.write(align_value);
        self
    }

    pub fn font(&mut self, family: &str) -> &mut Printer<W> {
        let family_upper = family.to_uppercase();
        let family_value = match family_upper.as_ref() {
            "A" => consts::TXT_FONT_A,
            "B" => consts::TXT_FONT_B,
            "C" => consts::TXT_FONT_C,
            _ => panic!("Invalid font family: {}", family)
        };
        let _ = self.write(family_value);
        self
    }

    pub fn style(&mut self, kind: &str) -> &mut Printer<W> {
        let kind_upper = kind.to_uppercase();
        match kind_upper.as_ref() {
            "B" => {
                let _ = self.write(consts::TXT_UNDERL_OFF);
                let _ = self.write(consts::TXT_BOLD_ON);
            }
            "U" => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL_ON);
            }
            "U2" => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL2_ON);
            }
            "BU" => {
                let _ = self.write(consts::TXT_BOLD_ON);
                let _ = self.write(consts::TXT_UNDERL_ON);
            }
            "BU2" => {
                let _ = self.write(consts::TXT_BOLD_ON);
                let _ = self.write(consts::TXT_UNDERL2_ON);
            }
            "NORMAL" | _ => {
                let _ = self.write(consts::TXT_BOLD_OFF);
                let _ = self.write(consts::TXT_UNDERL_OFF);
            }
        }
        self
    }

    pub fn size(&mut self, width: usize, height: usize) -> &mut Printer<W> {
        let _ = self.write(consts::TXT_NORMAL);
        if width == 2 {
            let _ = self.write(consts::TXT_2WIDTH);
        }
        if height == 2 {
            let _ = self.write(consts::TXT_2HEIGHT);
        }
        self
    }

    pub fn hardware(&mut self, hw: &str) -> &mut Printer<W> {
        let value = match hw {
            "INIT" => consts::HW_INIT,
            "SELECT" => consts::HW_SELECT,
            "RESET" => consts::HW_RESET,
            _ => panic!("Invalid hardware command: {}", hw)
        };
        let _ = self.write(value);
        self
    }

    pub fn barcode(&mut self,
                   code: &str,
                   kind: &str,
                   position: &str,
                   font: &str,
                   width: usize, height: usize) -> &mut Printer<W> {
        if width >= 1 || width <= 255 {
            let _ = self.write(consts::BARCODE_WIDTH);
        }
        if height >= 2 || height <= 6 {
            let _ = self.write(consts::BARCODE_HEIGHT);
        }

        let font = font.to_uppercase();
        let position = position.to_uppercase();
        let kind = kind.to_uppercase().replace("-", "_");
        let font_value = match font.as_ref() {
            "B" => consts::BARCODE_FONT_B,
            "A" | _ => consts::BARCODE_FONT_A
        };
        let txt_value = match position.as_ref() {
            "OFF" => consts::BARCODE_TXT_OFF,
            "ABV" => consts::BARCODE_TXT_ABV,
            "BTH" => consts::BARCODE_TXT_BTH,
            "BLW" | _ => consts::BARCODE_TXT_BLW,
        };
        let kind_value = match kind.as_ref() {
            "UPC_A"  => consts::BARCODE_UPC_A,
            "UPC_E"  => consts::BARCODE_UPC_E,
            "EAN8"   => consts::BARCODE_EAN8,
            "CODE39" => consts::BARCODE_CODE39,
            "ITF"    => consts::BARCODE_ITF,
            "NW7"    => consts::BARCODE_NW7,
            "EAN13" | _ => consts::BARCODE_EAN13
        };
        let _ = self.write(font_value);
        let _ = self.write(txt_value);
        let _ = self.write(kind_value);
        let _ = self.write(code.as_bytes());
        self
    }

    pub fn qrimage(&mut self) -> &mut Printer<W> {
        self
    }

    pub fn qrcode(&mut self,
                  code: &str,
                  version: Option<i32>,
                  level: &str,
                  size: Option<i32>) -> &mut Printer<W> {
        let level = level.to_uppercase();
        let level_value = match level.as_ref() {
            "M" => consts::QR_LEVEL_M,
            "Q" => consts::QR_LEVEL_Q,
            "H" => consts::QR_LEVEL_H,
            "L" | _ => consts::QR_LEVEL_L,
        };
        let _ = self.write(consts::TYPE_QR);
        let _ = self.write(consts::CODE2D);
        let _ = self.write_u8(version.unwrap_or(3) as u8);
        let _ = self.write(level_value);
        let _ = self.write_u8(size.unwrap_or(3) as u8);
        let _ = self.write_u16le(code.len() as u16);
        let _ = self.write(code.as_bytes());
        self
    }

    pub fn cashdraw(&mut self, pin: i32) -> &mut Printer<W> {
        let pin_value = if pin == 5 {
            consts::CD_KICK_5
        } else {
            consts::CD_KICK_2
        };
        let _ = self.write(pin_value);
        self
    }

    pub fn cut(&mut self, part: bool) -> &mut Printer<W> {
        self.print(iter::repeat(consts::EOL)
                   .take(3)
                   .collect::<String>()
                   .as_ref());
        let paper_cut_type = if part {
            consts::PAPER_PART_CUT
        } else {
            consts::PAPER_FULL_CUT
        };
        let _ = self.write(paper_cut_type);
        self
    }

    pub fn bit_image(&mut self,
                    image: &Image,
                    density: Option<&str>) -> &mut Printer<W> {
        let density = density.unwrap_or("d24");
        let density_upper = density.to_uppercase();
        let header = match density_upper.as_ref() {
            "S8"  => consts::BITMAP_S8,
            "D8"  => consts::BITMAP_D8,
            "S24" => consts::BITMAP_S24,
            "D24" | _ => consts::BITMAP_D24,
        };
        let n = if density == "s8" || density == "d8" { 1 } else { 3 };
        self.line_space(0);
        for line in image.bitimage_lines(n*8) {
            let _ = self.write(header);
            let _ = self.write_u16le((line.len() / n as usize) as u16);
            let _ = self.write(line.as_ref());
            self.feed(1);
        }
        self
    }

    pub fn raster(&mut self, image: &Image, mode: Option<&str>) -> &mut Printer<W> {
        let mode_upper = mode.unwrap_or("NORMAL").to_uppercase();
        let header = match mode_upper.as_ref() {
            "DH" => consts::GSV0_DH,
            "DWDH" => consts::GSV0_DWDH,
            "DW" | "NORMAL" | _ => consts::GSV0_DW,
        };
        let _ = self.write(header);
        let _ = self.write_u16le(image.width as u16);
        let _ = self.write_u16le(image.height as u16);
        let _ = self.write(image.get_raster().as_ref());
        self
    }
}
<|endoftext|>


<commit_before>use std::iter;
use super::stacks_and_queues::bag::{Bag, Iter};
use super::stacks_and_queues::{Stack, Queue};
use super::stacks_and_queues::linked_stack;
use super::stacks_and_queues::resizing_array_queue::ResizingArrayQueue;

#[derive(Clone, Debug)]
pub struct Digraph {
    v: usize,
    e: usize,
    adj: Vec<Bag<usize>>
}

impl Digraph {
    pub fn new(v: usize) -> Digraph {
        Digraph {
            v: v,
            e: 0,
            adj: iter::repeat(Bag::<usize>::new()).take(v).collect()
        }
    }

    fn validate_vertex(&self, v: usize) {
        assert!(v < self.v, "vertex is not between 0 and {}", self.v - 1)
    }

    pub fn vertices(&self) -> usize {
        self.v
    }

    pub fn edges(&self) -> usize {
        self.e
    }

    pub fn add_edge(&mut self, v: usize, w: usize) {
        self.validate_vertex(v);
        self.validate_vertex(w);

        self.e += 1;
        self.adj[v].add(w);
    }

    pub fn degree(&self, v: usize) -> usize {
        self.validate_vertex(v);
        self.adj[v].len()
    }

    pub fn max_degree(&self) -> usize {
        (0 .. self.vertices()).map(|v| self.degree(v)).max().unwrap_or(0)
    }

    pub fn average_degree(&self) -> f64 {
        // (0 .. self.vertices()) .map(|v| self.degree(v)).sum::<usize>() as f64 / self.vertices() as f64
        2.0 * self.edges() as f64 / self.vertices() as f64
    }

    pub fn number_of_self_loops(&self) -> usize {
        let mut count = 0;
        for v in 0 .. self.vertices() {
            for w in self.adj(v) {
                if v == *w {
                    count += 1;
                }
            }
        }
        count / 2
    }

    pub fn to_dot(&self) -> String {
        let mut dot = String::new();

        dot.push_str("digraph G {\n");
        for i in 0 .. self.v {
            dot.push_str(&format!("  {};\n", i));
        }

        for (v, adj) in self.adj.iter().enumerate() {
            for w in adj.iter() {
                dot.push_str(&format!("  {} -> {};\n", v, w));
            }
        }
        dot.push_str("}\n");
        dot
    }

    pub fn adj(&self, v: usize) -> Iter<usize> {
        self.adj[v].iter()
    }

    pub fn reverse(&self) -> Digraph {
        let v = self.v;
        let mut adj = iter::repeat(Bag::new()).take(v).collect::<Vec<Bag<usize>>>();
        for s in 0 .. v {
            for e in self.adj(s) {
                adj[*e].add(s);
            }
        }
        Digraph {
            v: v,
            e: self.e,
            adj: adj
        }
    }

    pub fn dfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, s);
        path.dfs(s);
        path
    }

    pub fn bfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, s);
        path.bfs(s);
        path
    }

    pub fn cc<'a>(&'a self) -> ConnectedComponents<'a> {
        ConnectedComponents::new(self)
    }
}

pub struct SearchPaths<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    edge_to: Vec<Option<usize>>,
    s: usize
}

impl<'a> SearchPaths<'a> {
    fn new<'b>(graph: &'b Digraph, s: usize) -> SearchPaths<'b> {
        let marked = iter::repeat(false).take(graph.vertices()).collect();
        let edge_to = iter::repeat(None).take(graph.vertices()).collect();
        SearchPaths {
            graph: graph,
            marked: marked,
            edge_to: edge_to,
            s: s
        }
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[*w] {
                self.dfs(*w);
                self.edge_to[*w] = Some(v);
            }
        }
    }

    fn bfs(&mut self, s: usize) {
        let mut q = ResizingArrayQueue::new();
        q.enqueue(s);
        self.marked[s] = true;
        while !q.is_empty() {
            let v = q.dequeue().unwrap();
            for w in self.graph.adj(v) {
                if !self.marked[*w] {
                    self.edge_to[*w] = Some(v);
                    q.enqueue(*w);
                    self.marked[*w] = true;
                }
            }
        }
    }

    pub fn has_path_to(&self, v: usize) -> bool {
        self.marked[v]
    }

    pub fn path_to(&self, v: usize) -> Option<Vec<usize>> {
        if !self.has_path_to(v) {
            None
        } else {
            let mut path = linked_stack::LinkedStack::new();
            let mut x = v;
            while x != self.s {
                path.push(x);
                x = self.edge_to[x].unwrap();
            }
            path.push(self.s);
            Some(path.into_iter().collect())
        }
    }
}

pub struct ConnectedComponents<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    id: Vec<Option<usize>>,
    n: usize,
    count: usize,
}

impl<'a> ConnectedComponents<'a> {
    fn new<'b>(graph: &'b Digraph) -> ConnectedComponents<'b> {
        let n = graph.vertices();
        let mut cc = ConnectedComponents {
            graph: graph,
            marked: iter::repeat(false).take(n).collect(),
            id: iter::repeat(None).take(n).collect(),
            n: n,
            count: 0
        };
        cc.init();
        cc
    }

    fn init(&mut self) {
        for v in 0 .. self.n {
            if !self.marked[v] {
                self.dfs(v);
                self.count += 1;
            }
        }
    }

    pub fn count(&self) -> usize {
        self.count
    }

    pub fn id(&self, v: usize) -> usize {
        self.id[v].unwrap()
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        self.id[v] = Some(self.count);
        for w in self.graph.adj(v) {
            if !self.marked[*w] {
                self.dfs(*w)
            }
        }
    }
}

#[test]
fn test_digraph_visit() {
    let mut g = Digraph::new(13);
    g.add_edge(0, 1);
    g.add_edge(2, 0);
    g.add_edge(6, 0);
    g.add_edge(0, 5);

    g.add_edge(3, 5);
    g.add_edge(5, 4);

    g.add_edge(2, 3);
    g.add_edge(3, 2);

    g.add_edge(4, 3);
    g.add_edge(4, 2);
    g.add_edge(6, 4);

    g.add_edge(6, 8);
    g.add_edge(8, 6);

    g.add_edge(7, 6);

    g.add_edge(7, 9);
    g.add_edge(6, 9);

    g.add_edge(9, 10);
    g.add_edge(10, 12);
    g.add_edge(9, 11);
    g.add_edge(12, 9);
    g.add_edge(11, 12);

    println!("dot => \n {}", g.to_dot());
    println!("dot => \n {}", g.reverse().to_dot());
    assert_eq!(format!("{:?}", g.dfs(0).path_to(3).unwrap()), "[0, 5, 4, 2, 3]");
    assert_eq!(format!("{:?}", g.bfs(0).path_to(3).unwrap()), "[0, 5, 4, 3]");

    // assert_eq!(g.cc().id(4), 0);
    // assert_eq!(g.cc().id(8), 1);
    // assert_eq!(g.cc().id(11), 2);
}

#[test]
fn test_digraph() {
    let mut g = Digraph::new(10);
    g.add_edge(0, 3);
    g.add_edge(0, 5);
    g.add_edge(4, 5);
    g.add_edge(2, 9);
    g.add_edge(2, 8);
    g.add_edge(3, 7);

    g.add_edge(1, 6);
    g.add_edge(6, 9);
    g.add_edge(5, 8);

    // println!("got => \n{}", g.to_dot());

    assert_eq!(10, g.vertices());
    assert_eq!(9, g.edges());
    assert_eq!(1, g.degree(5));

    for w in g.adj(5) {
        assert!(vec![8, 4, 0].contains(w));
    }

    assert_eq!(g.max_degree(), 2);
    assert!(g.average_degree() < 2.0);
    assert_eq!(g.number_of_self_loops(), 0);
}

#[test]
fn test_digraph_functions() {
    let mut g = Digraph::new(5);
    for i in 0 .. 5 {
        for j in 0 .. 5 {
            g.add_edge(i, j);
        }
    }

    assert_eq!(5, g.max_degree());
    assert_eq!(2, g.number_of_self_loops());
}
<commit_msg>directed_graphs: add depth first order; now adj() iter over usize instead of &usize<commit_after>use std::iter;
use super::stacks_and_queues::bag::Bag;
use super::stacks_and_queues::{Stack, Queue};
use super::stacks_and_queues::linked_stack;
use super::stacks_and_queues::resizing_array_queue::ResizingArrayQueue;

#[derive(Clone, Debug)]
pub struct Digraph {
    v: usize,
    e: usize,
    adj: Vec<Bag<usize>>
}

impl Digraph {
    pub fn new(v: usize) -> Digraph {
        Digraph {
            v: v,
            e: 0,
            adj: iter::repeat(Bag::<usize>::new()).take(v).collect()
        }
    }

    fn validate_vertex(&self, v: usize) {
        assert!(v < self.v, "vertex is not between 0 and {}", self.v - 1)
    }

    pub fn vertices(&self) -> usize {
        self.v
    }

    pub fn edges(&self) -> usize {
        self.e
    }

    pub fn add_edge(&mut self, v: usize, w: usize) {
        self.validate_vertex(v);
        self.validate_vertex(w);

        self.e += 1;
        self.adj[v].add(w);
    }

    pub fn outdegree(&self, v: usize) -> usize {
        self.validate_vertex(v);
        self.adj[v].len()
    }

    pub fn number_of_self_loops(&self) -> usize {
        let mut count = 0;
        for v in 0 .. self.vertices() {
            for w in self.adj(v) {
                if v == w {
                    count += 1;
                }
            }
        }
        count / 2
    }

    pub fn to_dot(&self) -> String {
        let mut dot = String::new();

        dot.push_str("digraph G {\n");
        for i in 0 .. self.v {
            dot.push_str(&format!("  {};\n", i));
        }

        for (v, adj) in self.adj.iter().enumerate() {
            for w in adj.iter() {
                dot.push_str(&format!("  {} -> {};\n", v, w));
            }
        }
        dot.push_str("}\n");
        dot
    }

    pub fn adj(&self, v: usize) -> ::std::vec::IntoIter<usize> {
        self.adj[v].iter().map(|v| v.clone()).collect::<Vec<usize>>().into_iter()
    }

    pub fn reverse(&self) -> Digraph {
        let v = self.v;
        let mut adj = iter::repeat(Bag::new()).take(v).collect::<Vec<Bag<usize>>>();
        for s in 0 .. v {
            for e in self.adj(s) {
                adj[e].add(s);
            }
        }
        Digraph {
            v: v,
            e: self.e,
            adj: adj
        }
    }

    pub fn dfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, s);
        path.dfs(s);
        path
    }

    pub fn bfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, s);
        path.bfs(s);
        path
    }

    pub fn reverse_dfs_postorder<'a>(&'a self) -> linked_stack::IntoIter<usize> {
        let mut dfo = DepthFirstOrder::new(self);
        dfo.init();
        dfo.reverse_post.into_iter()
    }
}

pub struct SearchPaths<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    edge_to: Vec<Option<usize>>,
    s: usize
}

impl<'a> SearchPaths<'a> {
    fn new<'b>(graph: &'b Digraph, s: usize) -> SearchPaths<'b> {
        let marked = iter::repeat(false).take(graph.vertices()).collect();
        let edge_to = iter::repeat(None).take(graph.vertices()).collect();
        SearchPaths {
            graph: graph,
            marked: marked,
            edge_to: edge_to,
            s: s
        }
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[w] {
                self.dfs(w);
                self.edge_to[w] = Some(v);
            }
        }
    }

    fn bfs(&mut self, s: usize) {
        let mut q = ResizingArrayQueue::new();
        q.enqueue(s);
        self.marked[s] = true;
        while !q.is_empty() {
            let v = q.dequeue().unwrap();
            for w in self.graph.adj(v) {
                if !self.marked[w] {
                    self.edge_to[w] = Some(v);
                    q.enqueue(w);
                    self.marked[w] = true;
                }
            }
        }
    }

    pub fn has_path_to(&self, v: usize) -> bool {
        self.marked[v]
    }

    pub fn path_to(&self, v: usize) -> Option<Vec<usize>> {
        if !self.has_path_to(v) {
            None
        } else {
            let mut path = linked_stack::LinkedStack::new();
            let mut x = v;
            while x != self.s {
                path.push(x);
                x = self.edge_to[x].unwrap();
            }
            path.push(self.s);
            Some(path.into_iter().collect())
        }
    }
}

pub struct DepthFirstOrder<'a> {
    graph: &'a Digraph,
    marked: Vec<bool>,
    reverse_post: linked_stack::LinkedStack<usize>
}

impl<'a> DepthFirstOrder<'a> {
    fn new<'b>(graph: &'b Digraph) -> DepthFirstOrder<'b> {
        let marked = iter::repeat(false).take(graph.vertices()).collect();
        DepthFirstOrder {
            graph: graph,
            marked: marked,
            reverse_post: Stack::new()
        }
    }

    fn init(&mut self) {
        for v in 0 .. self.graph.vertices() {
            if !self.marked[v] {
                self.dfs(v)
            }
        }
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[w] {
                self.dfs(w);
            }
        }
        self.reverse_post.push(v);
    }
}

#[test]
fn test_digraph_visit() {
    let mut g = Digraph::new(13);
    g.add_edge(0, 1);
    g.add_edge(2, 0);
    g.add_edge(6, 0);
    g.add_edge(0, 5);

    g.add_edge(3, 5);
    g.add_edge(5, 4);

    g.add_edge(2, 3);
    g.add_edge(3, 2);

    g.add_edge(4, 3);
    g.add_edge(4, 2);
    g.add_edge(6, 4);

    g.add_edge(6, 8);
    g.add_edge(8, 6);

    g.add_edge(7, 6);

    g.add_edge(7, 9);
    g.add_edge(6, 9);

    g.add_edge(9, 10);
    g.add_edge(10, 12);
    g.add_edge(9, 11);
    g.add_edge(12, 9);
    g.add_edge(11, 12);

    println!("dot => \n {}", g.to_dot());
    println!("dot => \n {}", g.reverse().to_dot());
    assert_eq!(format!("{:?}", g.dfs(0).path_to(3).unwrap()), "[0, 5, 4, 2, 3]");
    assert_eq!(format!("{:?}", g.bfs(0).path_to(3).unwrap()), "[0, 5, 4, 3]");

}

#[test]
fn test_digraph() {
    let mut g = Digraph::new(10);
    g.add_edge(0, 3);
    g.add_edge(0, 5);
    g.add_edge(4, 5);
    g.add_edge(2, 9);
    g.add_edge(2, 8);
    g.add_edge(3, 7);

    g.add_edge(1, 6);
    g.add_edge(6, 9);
    g.add_edge(5, 8);

    // println!("got => \n{}", g.to_dot());

    assert_eq!(10, g.vertices());
    assert_eq!(9, g.edges());
    assert_eq!(1, g.outdegree(5));

    for w in g.adj(5) {
        assert!(vec![8, 4, 0].contains(&w));
    }

    assert_eq!(g.number_of_self_loops(), 0);
}

#[test]
fn test_digraph_functions() {
    let mut g = Digraph::new(5);
    for i in 0 .. 5 {
        for j in 0 .. 5 {
            g.add_edge(i, j);
        }
    }

    assert_eq!(2, g.number_of_self_loops());
}

#[test]
fn test_digraph_depth_first_search_order() {
    let mut g = Digraph::new(7);
    g.add_edge(0, 2);
    g.add_edge(0, 5);
    g.add_edge(0, 1);
    g.add_edge(6, 0);
    g.add_edge(5, 2);
    g.add_edge(3, 2);
    g.add_edge(3, 5);
    g.add_edge(1, 4);
    g.add_edge(3, 4);
    g.add_edge(3, 6);
    g.add_edge(6, 4);

    let dfo: Vec<usize> = g.reverse_dfs_postorder().collect();
    assert_eq!(vec![3, 6, 0, 5, 2, 1, 4], dfo);
}
<|endoftext|>


<commit_before>//! Shadowsocks Server Context

use std::{
    io,
    net::IpAddr,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use bloomfilter::Bloom;
use spin::Mutex;
use tokio::runtime::Handle;
#[cfg(feature = "trust-dns")]
use trust_dns_resolver::TokioAsyncResolver;

use crate::config::{Config, ConfigType};
#[cfg(feature = "trust-dns")]
use crate::relay::dns_resolver::create_resolver;

// Entries for server's bloom filter
//
// Borrowed from shadowsocks-libev's default value
const BF_NUM_ENTRIES_FOR_SERVER: usize = 1_000_000;

// Entries for client's bloom filter
//
// Borrowed from shadowsocks-libev's default value
const BF_NUM_ENTRIES_FOR_CLIENT: usize = 10_000;

// Error rate for server's bloom filter
//
// Borrowed from shadowsocks-libev's default value
const BF_ERROR_RATE_FOR_SERVER: f64 = 1e-6;

// Error rate for client's bloom filter
//
// Borrowed from shadowsocks-libev's default value
const BF_ERROR_RATE_FOR_CLIENT: f64 = 1e-15;

// A bloom filter borrowed from shadowsocks-libev's `ppbloom`
//
// It contains 2 bloom filters and each one holds 1/2 entries.
// Use them as a ring buffer.
struct PingPongBloom {
    blooms: [Bloom<[u8]>; 2],
    bloom_count: [usize; 2],
    item_count: usize,
    current: usize,
}

impl PingPongBloom {
    fn new(ty: ConfigType) -> PingPongBloom {
        let (mut item_count, fp_p) = if ty.is_local() {
            (BF_NUM_ENTRIES_FOR_CLIENT, BF_ERROR_RATE_FOR_CLIENT)
        } else {
            (BF_NUM_ENTRIES_FOR_SERVER, BF_ERROR_RATE_FOR_SERVER)
        };

        item_count /= 2;

        PingPongBloom {
            blooms: [
                Bloom::new_for_fp_rate(item_count, fp_p),
                Bloom::new_for_fp_rate(item_count, fp_p),
            ],
            bloom_count: [0, 0],
            item_count,
            current: 0,
        }
    }

    // Check if data in `buf` exist.
    //
    // Set into the current bloom filter if not exist.
    //
    // Return `true` if data exist in bloom filter.
    fn check_and_set(&mut self, buf: &[u8]) -> bool {
        if self.bloom_count[self.current] >= self.item_count {
            // Current bloom filter is full,
            // Create a new one and use the next one as current.
            self.bloom_count[self.current] = 0;
            self.blooms[self.current].clear();

            self.current = (self.current + 1) % 2;
        }

        if !self.blooms[self.current].check_and_set(buf) {
            self.bloom_count[self.current] += 1;
            false
        } else {
            true
        }
    }
}

/// Server's global running status
///
/// Shared between UDP and TCP servers
pub struct ServerState {
    #[cfg(feature = "trust-dns")]
    dns_resolver: TokioAsyncResolver,
    server_running: AtomicBool,
    nonce_ppbloom: Mutex<PingPongBloom>,
}

impl ServerState {
    #[allow(unused_variables)]
    pub async fn new(config: &Config, rt: Handle) -> io::Result<SharedServerState> {
        let state = ServerState {
            #[cfg(feature = "trust-dns")]
            dns_resolver: create_resolver(config.get_dns_config(), rt).await?,
            server_running: AtomicBool::new(true),
            nonce_ppbloom: Mutex::new(PingPongBloom::new(config.config_type)),
        };

        Ok(Arc::new(state))
    }

    /// Check if the server is still in running state
    pub fn server_running(&self) -> bool {
        self.server_running.load(Ordering::Acquire)
    }

    /// Stops the server, kills all detached running tasks
    pub fn server_stopped(&self) {
        self.server_running.store(false, Ordering::Release)
    }

    /// Get the global shared resolver
    #[cfg(feature = "trust-dns")]
    pub fn dns_resolver(&self) -> &TokioAsyncResolver {
        &self.dns_resolver
    }

    /// Check if nonce exist or not
    ///
    /// If not, set into the current bloom filter
    pub fn check_nonce_and_set(&self, nonce: &[u8]) -> bool {
        let mut ppbloom = self.nonce_ppbloom.lock();
        ppbloom.check_and_set(nonce)
    }
}

/// `ServerState` wrapped in `Arc`
pub type SharedServerState = Arc<ServerState>;

/// Shared basic configuration for the whole server
pub struct Context {
    config: Config,
    server_state: SharedServerState,
}

/// Unique context thw whole server
pub type SharedContext = Arc<Context>;

impl Context {
    /// Create a non-shared Context
    pub fn new(config: Config, server_state: SharedServerState) -> Context {
        Context { config, server_state }
    }

    /// Create a shared Context, wrapped in `Arc`
    pub fn new_shared(config: Config, server_state: SharedServerState) -> SharedContext {
        SharedContext::new(Context::new(config, server_state))
    }

    /// Clone the internal `ServerState`
    pub fn clone_server_state(&self) -> SharedServerState {
        self.server_state.clone()
    }

    /// Config for TCP server
    pub fn config(&self) -> &Config {
        &self.config
    }

    /// Mutable Config for TCP server
    ///
    /// NOTE: Only for launching plugins
    pub fn config_mut(&mut self) -> &mut Config {
        &mut self.config
    }

    #[cfg(feature = "trust-dns")]
    /// Get the global shared resolver
    pub fn dns_resolver(&self) -> &TokioAsyncResolver {
        self.server_state.dns_resolver()
    }

    /// Check if the server is still in running state
    pub fn server_running(&self) -> bool {
        self.server_state.server_running()
    }

    /// Stops the server, kills all detached running tasks
    pub fn server_stopped(&self) {
        self.server_state.server_stopped()
    }

    /// Check if IP is in forbidden list
    pub fn check_forbidden_ip(&self, ip: &IpAddr) -> bool {
        self.config.check_forbidden_ip(ip)
    }

    /// Check if nonce exist or not
    ///
    /// If not, set into the current bloom filter
    pub fn check_nonce_and_set(&self, nonce: &[u8]) -> bool {
        self.server_state.check_nonce_and_set(nonce)
    }
}
<commit_msg>Check every filters instead of only the current one<commit_after>//! Shadowsocks Server Context

use std::{
    io,
    net::IpAddr,
    sync::{
        atomic::{AtomicBool, Ordering},
        Arc,
    },
};

use bloomfilter::Bloom;
use spin::Mutex;
use tokio::runtime::Handle;
#[cfg(feature = "trust-dns")]
use trust_dns_resolver::TokioAsyncResolver;

use crate::config::{Config, ConfigType};
#[cfg(feature = "trust-dns")]
use crate::relay::dns_resolver::create_resolver;

// Entries for server's bloom filter
//
// Borrowed from shadowsocks-libev's default value
const BF_NUM_ENTRIES_FOR_SERVER: usize = 1_000_000;

// Entries for client's bloom filter
//
// Borrowed from shadowsocks-libev's default value
const BF_NUM_ENTRIES_FOR_CLIENT: usize = 10_000;

// Error rate for server's bloom filter
//
// Borrowed from shadowsocks-libev's default value
const BF_ERROR_RATE_FOR_SERVER: f64 = 1e-6;

// Error rate for client's bloom filter
//
// Borrowed from shadowsocks-libev's default value
const BF_ERROR_RATE_FOR_CLIENT: f64 = 1e-15;

// A bloom filter borrowed from shadowsocks-libev's `ppbloom`
//
// It contains 2 bloom filters and each one holds 1/2 entries.
// Use them as a ring buffer.
struct PingPongBloom {
    blooms: [Bloom<[u8]>; 2],
    bloom_count: [usize; 2],
    item_count: usize,
    current: usize,
}

impl PingPongBloom {
    fn new(ty: ConfigType) -> PingPongBloom {
        let (mut item_count, fp_p) = if ty.is_local() {
            (BF_NUM_ENTRIES_FOR_CLIENT, BF_ERROR_RATE_FOR_CLIENT)
        } else {
            (BF_NUM_ENTRIES_FOR_SERVER, BF_ERROR_RATE_FOR_SERVER)
        };

        item_count /= 2;

        PingPongBloom {
            blooms: [
                Bloom::new_for_fp_rate(item_count, fp_p),
                Bloom::new_for_fp_rate(item_count, fp_p),
            ],
            bloom_count: [0, 0],
            item_count,
            current: 0,
        }
    }

    // Check if data in `buf` exist.
    //
    // Set into the current bloom filter if not exist.
    //
    // Return `true` if data exist in bloom filter.
    fn check_and_set(&mut self, buf: &[u8]) -> bool {
        for bloom in &self.blooms {
            if bloom.check(buf) {
                return true;
            }
        }

        if self.bloom_count[self.current] >= self.item_count {
            // Current bloom filter is full,
            // Create a new one and use the next one as current.
            self.bloom_count[self.current] = 0;
            self.blooms[self.current].clear();

            self.current = (self.current + 1) % 2;
        }

        // Cannot be optimized by `check_and_set`
        // Because we have to check every filters in `blooms` before `set`
        self.blooms[self.current].set(buf);
        self.bloom_count[self.current] += 1;

        false
    }
}

/// Server's global running status
///
/// Shared between UDP and TCP servers
pub struct ServerState {
    #[cfg(feature = "trust-dns")]
    dns_resolver: TokioAsyncResolver,
    server_running: AtomicBool,
    nonce_ppbloom: Mutex<PingPongBloom>,
}

impl ServerState {
    #[allow(unused_variables)]
    pub async fn new(config: &Config, rt: Handle) -> io::Result<SharedServerState> {
        let state = ServerState {
            #[cfg(feature = "trust-dns")]
            dns_resolver: create_resolver(config.get_dns_config(), rt).await?,
            server_running: AtomicBool::new(true),
            nonce_ppbloom: Mutex::new(PingPongBloom::new(config.config_type)),
        };

        Ok(Arc::new(state))
    }

    /// Check if the server is still in running state
    pub fn server_running(&self) -> bool {
        self.server_running.load(Ordering::Acquire)
    }

    /// Stops the server, kills all detached running tasks
    pub fn server_stopped(&self) {
        self.server_running.store(false, Ordering::Release)
    }

    /// Get the global shared resolver
    #[cfg(feature = "trust-dns")]
    pub fn dns_resolver(&self) -> &TokioAsyncResolver {
        &self.dns_resolver
    }

    /// Check if nonce exist or not
    ///
    /// If not, set into the current bloom filter
    pub fn check_nonce_and_set(&self, nonce: &[u8]) -> bool {
        let mut ppbloom = self.nonce_ppbloom.lock();
        ppbloom.check_and_set(nonce)
    }
}

/// `ServerState` wrapped in `Arc`
pub type SharedServerState = Arc<ServerState>;

/// Shared basic configuration for the whole server
pub struct Context {
    config: Config,
    server_state: SharedServerState,
}

/// Unique context thw whole server
pub type SharedContext = Arc<Context>;

impl Context {
    /// Create a non-shared Context
    pub fn new(config: Config, server_state: SharedServerState) -> Context {
        Context { config, server_state }
    }

    /// Create a shared Context, wrapped in `Arc`
    pub fn new_shared(config: Config, server_state: SharedServerState) -> SharedContext {
        SharedContext::new(Context::new(config, server_state))
    }

    /// Clone the internal `ServerState`
    pub fn clone_server_state(&self) -> SharedServerState {
        self.server_state.clone()
    }

    /// Config for TCP server
    pub fn config(&self) -> &Config {
        &self.config
    }

    /// Mutable Config for TCP server
    ///
    /// NOTE: Only for launching plugins
    pub fn config_mut(&mut self) -> &mut Config {
        &mut self.config
    }

    #[cfg(feature = "trust-dns")]
    /// Get the global shared resolver
    pub fn dns_resolver(&self) -> &TokioAsyncResolver {
        self.server_state.dns_resolver()
    }

    /// Check if the server is still in running state
    pub fn server_running(&self) -> bool {
        self.server_state.server_running()
    }

    /// Stops the server, kills all detached running tasks
    pub fn server_stopped(&self) {
        self.server_state.server_stopped()
    }

    /// Check if IP is in forbidden list
    pub fn check_forbidden_ip(&self, ip: &IpAddr) -> bool {
        self.config.check_forbidden_ip(ip)
    }

    /// Check if nonce exist or not
    ///
    /// If not, set into the current bloom filter
    pub fn check_nonce_and_set(&self, nonce: &[u8]) -> bool {
        self.server_state.check_nonce_and_set(nonce)
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::BTreeMap;

use serde::ser::Serialize;
use serde_json::value::{to_value, Map, Value};

use crate::errors::{Error, Result as TeraResult};

/// The struct that holds the context of a template rendering.
///
/// Light wrapper around a `BTreeMap` for easier insertions of Serializable
/// values
#[derive(Debug, Clone, PartialEq)]
pub struct Context {
    data: BTreeMap<String, Value>,
}

impl Context {
    /// Initializes an empty context
    pub fn new() -> Self {
        Context { data: BTreeMap::new() }
    }

    /// Converts the `val` parameter to `Value` and insert it into the context
    ///
    /// ```rust,ignore
    /// let mut context = Context::new();
    /// // user is an instance of a struct implementing `Serialize`
    /// context.insert("number_users", 42);
    /// ```
    pub fn insert<T: Serialize + ?Sized, S: Into<String>>(&mut self, key: S, val: &T) {
        self.data.insert(key.into(), to_value(val).unwrap());
    }

    /// Appends the data of the `source` parameter to `self`, overwriting existing keys.
    /// The source context will be dropped.
    ///
    /// ```rust,ignore
    /// let mut target = Context::new();
    /// target.insert("a", 1);
    /// target.insert("b", 2);
    /// let mut source = Context::new();
    /// source.insert("b", 3);
    /// source.insert("d", 4);
    /// target.extend(source);
    /// ```
    pub fn extend(&mut self, mut source: Context) {
        self.data.append(&mut source.data);
    }

    /// Converts the context to a `serde_json::Value` consuming the context
    pub fn into_json(self) -> Value {
        let mut m = Map::new();
        for (key, value) in self.data {
            m.insert(key, value);
        }
        Value::Object(m)
    }

    /// Takes a serde-json `Value` and convert it into a `Context` with no overhead/cloning
    pub fn from_value(obj: Value) -> TeraResult<Self> {
        match obj {
            Value::Object(m) => {
                let mut data = BTreeMap::new();
                for (key, value) in m {
                    data.insert(key, value);
                }
                Ok(Context { data })
            }
            _ => Err(Error::msg(
                "Creating a Context from a Value/Serialize requires it being a JSON object",
            )),
        }
    }

    /// Takes something that impl Serialize and create a context with it.
    /// Meant to be used if you have a hashmap or a struct and don't want to insert values
    /// one by one in the context
    pub fn from_serialize(value: impl Serialize) -> TeraResult<Self> {
        let obj = to_value(value).map_err(Error::json)?;
        Context::from_value(obj)
    }

    pub(crate) fn get(&self, index: &str) -> Option<&Value> {
        self.data.get(index)
    }
}

impl Default for Context {
    fn default() -> Context {
        Context::new()
    }
}

pub trait ValueRender {
    fn render(&self) -> Cow<str>;
}

// Convert serde Value to String
impl ValueRender for Value {
    fn render(&self) -> Cow<str> {
        match *self {
            Value::String(ref s) => Cow::Borrowed(s),
            Value::Number(ref i) => Cow::Owned(i.to_string()),
            Value::Bool(i) => Cow::Owned(i.to_string()),
            Value::Null => Cow::Owned(String::new()),
            Value::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    if buf.len() > 1 {
                        buf.push_str(", ");
                    }
                    buf.push_str(i.render().as_ref());
                }
                buf.push(']');
                Cow::Owned(buf)
            }
            Value::Object(_) => Cow::Borrowed("[object]"),
        }
    }
}

pub trait ValueNumber {
    fn to_number(&self) -> Result<f64, ()>;
}
// Needed for all the maths
// Convert everything to f64, seems like a terrible idea
impl ValueNumber for Value {
    fn to_number(&self) -> Result<f64, ()> {
        match *self {
            Value::Number(ref i) => Ok(i.as_f64().unwrap()),
            _ => Err(()),
        }
    }
}

// From handlebars-rust
pub trait ValueTruthy {
    fn is_truthy(&self) -> bool;
}

impl ValueTruthy for Value {
    fn is_truthy(&self) -> bool {
        match *self {
            Value::Number(ref i) => {
                if i.is_i64() {
                    return i.as_i64().unwrap() != 0;
                }
                if i.is_u64() {
                    return i.as_u64().unwrap() != 0;
                }
                let f = i.as_f64().unwrap();
                f != 0.0 && !f.is_nan()
            }
            Value::Bool(ref i) => *i,
            Value::Null => false,
            Value::String(ref i) => !i.is_empty(),
            Value::Array(ref i) => !i.is_empty(),
            Value::Object(ref i) => !i.is_empty(),
        }
    }
}

/// Converts a dotted path to a json pointer one
#[inline]
pub fn get_json_pointer(key: &str) -> String {
    ["/", &key.replace(".", "/")].join("")
}

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

    use serde_json::json;
    use std::collections::HashMap;

    #[test]
    fn can_extend_context() {
        let mut target = Context::new();
        target.insert("a", &1);
        target.insert("b", &2);
        let mut source = Context::new();
        source.insert("b", &3);
        source.insert("c", &4);
        target.extend(source);
        assert_eq!(*target.data.get("a").unwrap(), to_value(1).unwrap());
        assert_eq!(*target.data.get("b").unwrap(), to_value(3).unwrap());
        assert_eq!(*target.data.get("c").unwrap(), to_value(4).unwrap());
    }

    #[test]
    fn can_create_context_from_value() {
        let obj = json!({
            "name": "bob",
            "age": 25
        });
        let context_from_value = Context::from_value(obj).unwrap();
        let mut context = Context::new();
        context.insert("name", "bob");
        context.insert("age", &25);
        assert_eq!(context_from_value, context);
    }

    #[test]
    fn can_create_context_from_impl_serialize() {
        let mut map = HashMap::new();
        map.insert("name", "bob");
        map.insert("last_name", "something");
        let context_from_serialize = Context::from_serialize(&map).unwrap();
        let mut context = Context::new();
        context.insert("name", "bob");
        context.insert("last_name", "something");
        assert_eq!(context_from_serialize, context);
    }
}
<commit_msg>feat(context): add `contains_key` and `get` methods (#540)<commit_after>use std::borrow::Cow;
use std::collections::BTreeMap;

use serde::ser::Serialize;
use serde_json::value::{to_value, Map, Value};

use crate::errors::{Error, Result as TeraResult};

/// The struct that holds the context of a template rendering.
///
/// Light wrapper around a `BTreeMap` for easier insertions of Serializable
/// values
#[derive(Debug, Clone, PartialEq)]
pub struct Context {
    data: BTreeMap<String, Value>,
}

impl Context {
    /// Initializes an empty context
    pub fn new() -> Self {
        Context { data: BTreeMap::new() }
    }

    /// Converts the `val` parameter to `Value` and insert it into the context
    ///
    /// ```rust,ignore
    /// let mut context = Context::new();
    /// // user is an instance of a struct implementing `Serialize`
    /// context.insert("number_users", 42);
    /// ```
    pub fn insert<T: Serialize + ?Sized, S: Into<String>>(&mut self, key: S, val: &T) {
        self.data.insert(key.into(), to_value(val).unwrap());
    }

    /// Appends the data of the `source` parameter to `self`, overwriting existing keys.
    /// The source context will be dropped.
    ///
    /// ```rust,ignore
    /// let mut target = Context::new();
    /// target.insert("a", 1);
    /// target.insert("b", 2);
    /// let mut source = Context::new();
    /// source.insert("b", 3);
    /// source.insert("d", 4);
    /// target.extend(source);
    /// ```
    pub fn extend(&mut self, mut source: Context) {
        self.data.append(&mut source.data);
    }

    /// Converts the context to a `serde_json::Value` consuming the context
    pub fn into_json(self) -> Value {
        let mut m = Map::new();
        for (key, value) in self.data {
            m.insert(key, value);
        }
        Value::Object(m)
    }

    /// Takes a serde-json `Value` and convert it into a `Context` with no overhead/cloning
    pub fn from_value(obj: Value) -> TeraResult<Self> {
        match obj {
            Value::Object(m) => {
                let mut data = BTreeMap::new();
                for (key, value) in m {
                    data.insert(key, value);
                }
                Ok(Context { data })
            }
            _ => Err(Error::msg(
                "Creating a Context from a Value/Serialize requires it being a JSON object",
            )),
        }
    }

    /// Takes something that impl Serialize and create a context with it.
    /// Meant to be used if you have a hashmap or a struct and don't want to insert values
    /// one by one in the context
    pub fn from_serialize(value: impl Serialize) -> TeraResult<Self> {
        let obj = to_value(value).map_err(Error::json)?;
        Context::from_value(obj)
    }

    /// Returns the value at a given key index.
    pub fn get(&self, index: &str) -> Option<&Value> {
        self.data.get(index)
    }

    /// Checks if a value exists at a specific index.
    pub fn contains_key(&self, index: &str) -> bool {
        self.data.contains_key(index)
    }
}

impl Default for Context {
    fn default() -> Context {
        Context::new()
    }
}

pub trait ValueRender {
    fn render(&self) -> Cow<str>;
}

// Convert serde Value to String
impl ValueRender for Value {
    fn render(&self) -> Cow<str> {
        match *self {
            Value::String(ref s) => Cow::Borrowed(s),
            Value::Number(ref i) => Cow::Owned(i.to_string()),
            Value::Bool(i) => Cow::Owned(i.to_string()),
            Value::Null => Cow::Owned(String::new()),
            Value::Array(ref a) => {
                let mut buf = String::new();
                buf.push('[');
                for i in a.iter() {
                    if buf.len() > 1 {
                        buf.push_str(", ");
                    }
                    buf.push_str(i.render().as_ref());
                }
                buf.push(']');
                Cow::Owned(buf)
            }
            Value::Object(_) => Cow::Borrowed("[object]"),
        }
    }
}

pub trait ValueNumber {
    fn to_number(&self) -> Result<f64, ()>;
}
// Needed for all the maths
// Convert everything to f64, seems like a terrible idea
impl ValueNumber for Value {
    fn to_number(&self) -> Result<f64, ()> {
        match *self {
            Value::Number(ref i) => Ok(i.as_f64().unwrap()),
            _ => Err(()),
        }
    }
}

// From handlebars-rust
pub trait ValueTruthy {
    fn is_truthy(&self) -> bool;
}

impl ValueTruthy for Value {
    fn is_truthy(&self) -> bool {
        match *self {
            Value::Number(ref i) => {
                if i.is_i64() {
                    return i.as_i64().unwrap() != 0;
                }
                if i.is_u64() {
                    return i.as_u64().unwrap() != 0;
                }
                let f = i.as_f64().unwrap();
                f != 0.0 && !f.is_nan()
            }
            Value::Bool(ref i) => *i,
            Value::Null => false,
            Value::String(ref i) => !i.is_empty(),
            Value::Array(ref i) => !i.is_empty(),
            Value::Object(ref i) => !i.is_empty(),
        }
    }
}

/// Converts a dotted path to a json pointer one
#[inline]
pub fn get_json_pointer(key: &str) -> String {
    ["/", &key.replace(".", "/")].join("")
}

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

    use serde_json::json;
    use std::collections::HashMap;

    #[test]
    fn can_extend_context() {
        let mut target = Context::new();
        target.insert("a", &1);
        target.insert("b", &2);
        let mut source = Context::new();
        source.insert("b", &3);
        source.insert("c", &4);
        target.extend(source);
        assert_eq!(*target.data.get("a").unwrap(), to_value(1).unwrap());
        assert_eq!(*target.data.get("b").unwrap(), to_value(3).unwrap());
        assert_eq!(*target.data.get("c").unwrap(), to_value(4).unwrap());
    }

    #[test]
    fn can_create_context_from_value() {
        let obj = json!({
            "name": "bob",
            "age": 25
        });
        let context_from_value = Context::from_value(obj).unwrap();
        let mut context = Context::new();
        context.insert("name", "bob");
        context.insert("age", &25);
        assert_eq!(context_from_value, context);
    }

    #[test]
    fn can_create_context_from_impl_serialize() {
        let mut map = HashMap::new();
        map.insert("name", "bob");
        map.insert("last_name", "something");
        let context_from_serialize = Context::from_serialize(&map).unwrap();
        let mut context = Context::new();
        context.insert("name", "bob");
        context.insert("last_name", "something");
        assert_eq!(context_from_serialize, context);
    }
}
<|endoftext|>