<commit_before>use std::marker::PhantomData;
use std::iter::FromIterator;
use std::ops::{
    Range,
    RangeFrom,
    RangeFull,
    RangeTo,
};
use std::cmp::max;

use {Input, ParseResult};
use primitives::{InputClone, InputBuffer, IntoInner, State};

/// Internal macro to provide speedup for `FromIterator::from_iter`.
///
/// Needed as of rustc 1.7.0-nightly (81ae8be71 2015-12-09).
macro_rules! run_from_iter(
    ( $iter:ident as $r_ty:ty ) => {
        {
            // Dummy variable to tie the scope of the iteration into the current scope,
            // this causes rustc to inline `Iterator::next` into this scope including
            // `FromIterator::from_iter`.
            // This is probably how it works, #[inline] and #[inline(always)] do not affect it as
            // of rustc 1.7.0-nightly (81ae8be71 2015-12-09).
            let mut item = false;

            // the inspect() is useless here, but ties the inner scope of the loop to the current
            // scope which will make it inline `Iterator::next`.
            let result: T = FromIterator::from_iter($iter.by_ref().inspect(|_| item = true));

            // Oddly enough, no inspect() is much much slower:
            //
            // ```
            // let result: $r_ty = FromIterator::from_iter($iter.by_ref());
            // ```
            //
            // The above code is only faster in very very small benchmarks, anything larger than
            // the benchmarks for many (ie. multiple `many(i, any)`) will most likely be slower
            // when using the above line.

            // The performance difference is definitely noticeable in benchmarks, parsing 10k bytes of
            // any type and just storing them in a Vec is 10x slower on current nightly
            // (rustc 1.7.0-nightly (81ae8be71 2015-12-09)).

            (result, $iter.end_state())
        }
    }
);

/// Macro to implement a parser iterator, it provides the ability to add an extra state variable
/// into it and also provide a size_hint as well as a pre- and on-next hooks.
macro_rules! impl_iter {
    ( $iter_name:ident ( $data_ty:ty ) {
        size_hint($size_hint_self:ident) $size_hint:block

        next($next_self:ident) {
            pre $pre_next:block
            on  $on_next:block
        }
    } ) => {
        enum EndState<'a, I, E>
          where I: 'a {
            Error(&'a [I], E),
            Incomplete(usize),
        }

        struct $iter_name<'a, I, T, E, F>
          where I: 'a,
                T: 'a,
                E: 'a,
                F: FnMut(Input<'a, I>) -> ParseResult<'a, I, T, E> {
            /// Last state of the parser
            state:  EndState<'a, I, E>,
            /// Parser to execute once for each iteration
            parser: F,
            /// Remaining buffer
            buf:    Input<'a, I>,
            /// Nested state
            data:   $data_ty,
            _t:     PhantomData<T>,
        }

        impl<'a, I, T, E, F> $iter_name<'a, I, T, E, F>
          where I: 'a,
                T: 'a,
                E: 'a,
                F: FnMut(Input<'a, I>) -> ParseResult<'a, I, T, E> {
            #[inline(always)]
            fn end_state(self) -> (Input<'a, I>, $data_ty, EndState<'a, I, E>) {
                (self.buf, self.data, self.state)
            }
        }

        impl<'a, I, T, E, F> Iterator for $iter_name<'a, I, T, E, F>
          where I: 'a,
                T: 'a,
                E: 'a,
                F: FnMut(Input<'a, I>) -> ParseResult<'a, I, T, E> {
            type Item = T;

            #[inline(always)]
            fn size_hint(&$size_hint_self) -> (usize, Option<usize>) {
                $size_hint
            }

            #[inline(always)]
            fn next(&mut $next_self) -> Option<Self::Item> {
                $pre_next

                match ($next_self.parser)($next_self.buf.clone()).into_inner() {
                    State::Data(b, v) => {
                        $next_self.buf    = b;

                        $on_next

                        Some(v)
                    },
                    State::Error(b, e) => {
                        $next_self.state = EndState::Error(b, e);

                        None
                    },
                    State::Incomplete(n) => {
                        $next_self.state = EndState::Incomplete(n);

                        None
                    },
                }
            }
        }
    };
    ( $iter_name:ident ( $data_ty:ty ) {
        size_hint($size_hint_self:ident) $size_hint:block
    } ) => {
        impl_iter!($iter_name ( $data_ty ) {
            size_hint ( $size_hint_self ) $size_hint

            next(self) {
                pre {}
                on  {}
            }
        })
    };
}

/// Trait for iterating a parser based on a range.
pub trait BoundedRange {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U>;
}

impl BoundedRange for Range<usize> {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(ToIter((usize, usize)) {
            size_hint(self) {
                (self.data.0, Some(self.data.1))
            }

            next(self) {
                pre {
                    if self.data.1 == 0 {
                        return None;
                    }
                }
                on {
                    self.data.0  = if self.data.0 == 0 { 0 } else { self.data.0 - 1 };
                    self.data.1 -= 1;
                }
            }
        });

        let mut iter = ToIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // Range is closed on left side, open on right, ie. [self.start, self.end)
            data:   (self.start, max(self.end, 1) - 1),
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            // Got all occurrences of the parser
            (s, (0, 0), _) => s.ret(result),
            // Ok, last parser failed and we have reached minimum, we have iterated all.
            // Return remainder of buffer and the collected result
            (s, (0, _), EndState::Error(_, _))   => s.ret(result),
            // Nested parser incomplete but reached at least minimum, propagate if not at end
            (s, (0, _), EndState::Incomplete(n)) => if s.buffer().len() == 0 && s.is_last_slice() {
                s.ret(result)
            } else {
                s.incomplete(n)
            },
            // Did not reach minimum, propagate
            (s, (_, _), EndState::Error(b, e))   => s.replace(b).err(e),
            (s, (_, _), EndState::Incomplete(n)) => s.incomplete(n),
        }
    }
}

impl BoundedRange for RangeFrom<usize> {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(FromIter(usize) {
            size_hint(self) {
                (self.data, None)
            }

            next(self) {
                pre {}
                on  {
                    self.data = if self.data == 0 { 0 } else { self.data - 1 };
                }
            }
        });

        let mut iter = FromIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // Inclusive
            data:   self.start,
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            // We got at least n items
            (s, 0, EndState::Error(_, _))   => s.ret(result),
            // Nested parser incomplete, propagate if not at end
            (s, 0, EndState::Incomplete(n)) => if s.buffer().len() == 0 && s.is_last_slice() {
                s.ret(result)
            } else {
                s.incomplete(n)
            },
            // Items still remaining, propagate
            (s, _, EndState::Error(b, e))   => s.replace(b).err(e),
            (s, _, EndState::Incomplete(n)) => s.incomplete(n),
        }
    }
}

impl BoundedRange for RangeFull {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(ManyIter(()) {
            size_hint(self) {
                (0, None)
            }
        });

        let mut iter = ManyIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // No data required
            data:   (),
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            (s, (), EndState::Error(_, _))   => s.ret(result),
            // Nested parser incomplete, propagate if not at end
            (s, (), EndState::Incomplete(n)) => if s.buffer().len() == 0 && s.is_last_slice() {
                s.ret(result)
            } else {
                s.incomplete(n)
            },
        }
    }
}

impl BoundedRange for RangeTo<usize> {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(ToIter(usize) {
            size_hint(self) {
                (0, Some(self.data))
            }

            next(self) {
                pre {
                    if self.data == 0 {
                        return None;
                    }
                }
                on {
                    self.data  -= 1;
                }
            }
        });

        let mut iter = ToIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // Exclusive range [0, end)
            data:   max(self.end, 1) - 1,
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            // Either error or incomplete after the end
            (s, 0, _)                       => s.ret(result),
            // Inside of range, never outside
            (s, _, EndState::Error(_, _))   => s.ret(result),
            // Nested parser incomplete, propagate if not at end
            (s, _, EndState::Incomplete(n)) => if s.buffer().len() == 0 && s.is_last_slice() {
                s.ret(result)
            } else {
                s.incomplete(n)
            },
        }
    }
}

impl BoundedRange for usize {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(ToIter(usize) {
            size_hint(self) {
                (self.data, Some(self.data))
            }

            next(self) {
                pre {
                    if self.data == 0 {
                        return None;
                    }
                }
                on {
                    self.data  -= 1;
                }
            }
        });

        let mut iter = ToIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // Excatly self
            data:   *self,
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            // Got exact
            (s, 0, _)                       => s.ret(result),
            // We have got too few items, propagate error
            (s, _, EndState::Error(b, e))   => s.replace(b).err(e),
            // Nested parser incomplete, propagate
            (s, _, EndState::Incomplete(n)) => s.incomplete(n),
        }
    }
}

#[inline]
pub fn many<'a, I, T, E, F, U, R>(i: Input<'a, I>, r: R, f: F) -> ParseResult<'a, I, T, E>
  where I: Copy,
        R: BoundedRange,
        U: 'a,
        F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
        T: FromIterator<U> {
    BoundedRange::parse(&r, i, f)
}
<commit_msg>many, many1, sep_by, sep_by1: Do not consider a partial match incomplete as long as the range has been satisfied<commit_after>use std::marker::PhantomData;
use std::iter::FromIterator;
use std::ops::{
    Range,
    RangeFrom,
    RangeFull,
    RangeTo,
};
use std::cmp::max;

use {Input, ParseResult};
use primitives::{InputClone, InputBuffer, IntoInner, State};

/// Internal macro to provide speedup for `FromIterator::from_iter`.
///
/// Needed as of rustc 1.7.0-nightly (81ae8be71 2015-12-09).
macro_rules! run_from_iter(
    ( $iter:ident as $r_ty:ty ) => {
        {
            // Dummy variable to tie the scope of the iteration into the current scope,
            // this causes rustc to inline `Iterator::next` into this scope including
            // `FromIterator::from_iter`.
            // This is probably how it works, #[inline] and #[inline(always)] do not affect it as
            // of rustc 1.7.0-nightly (81ae8be71 2015-12-09).
            let mut item = false;

            // the inspect() is useless here, but ties the inner scope of the loop to the current
            // scope which will make it inline `Iterator::next`.
            let result: T = FromIterator::from_iter($iter.by_ref().inspect(|_| item = true));

            // Oddly enough, no inspect() is much much slower:
            //
            // ```
            // let result: $r_ty = FromIterator::from_iter($iter.by_ref());
            // ```
            //
            // The above code is only faster in very very small benchmarks, anything larger than
            // the benchmarks for many (ie. multiple `many(i, any)`) will most likely be slower
            // when using the above line.

            // The performance difference is definitely noticeable in benchmarks, parsing 10k bytes of
            // any type and just storing them in a Vec is 10x slower on current nightly
            // (rustc 1.7.0-nightly (81ae8be71 2015-12-09)).

            (result, $iter.end_state())
        }
    }
);

/// Macro to implement a parser iterator, it provides the ability to add an extra state variable
/// into it and also provide a size_hint as well as a pre- and on-next hooks.
macro_rules! impl_iter {
    ( $iter_name:ident ( $data_ty:ty ) {
        size_hint($size_hint_self:ident) $size_hint:block

        next($next_self:ident) {
            pre $pre_next:block
            on  $on_next:block
        }
    } ) => {
        enum EndState<'a, I, E>
          where I: 'a {
            Error(&'a [I], E),
            Incomplete(usize),
        }

        struct $iter_name<'a, I, T, E, F>
          where I: 'a,
                T: 'a,
                E: 'a,
                F: FnMut(Input<'a, I>) -> ParseResult<'a, I, T, E> {
            /// Last state of the parser
            state:  EndState<'a, I, E>,
            /// Parser to execute once for each iteration
            parser: F,
            /// Remaining buffer
            buf:    Input<'a, I>,
            /// Nested state
            data:   $data_ty,
            _t:     PhantomData<T>,
        }

        impl<'a, I, T, E, F> $iter_name<'a, I, T, E, F>
          where I: 'a,
                T: 'a,
                E: 'a,
                F: FnMut(Input<'a, I>) -> ParseResult<'a, I, T, E> {
            #[inline(always)]
            fn end_state(self) -> (Input<'a, I>, $data_ty, EndState<'a, I, E>) {
                (self.buf, self.data, self.state)
            }
        }

        impl<'a, I, T, E, F> Iterator for $iter_name<'a, I, T, E, F>
          where I: 'a,
                T: 'a,
                E: 'a,
                F: FnMut(Input<'a, I>) -> ParseResult<'a, I, T, E> {
            type Item = T;

            #[inline(always)]
            fn size_hint(&$size_hint_self) -> (usize, Option<usize>) {
                $size_hint
            }

            #[inline(always)]
            fn next(&mut $next_self) -> Option<Self::Item> {
                $pre_next

                match ($next_self.parser)($next_self.buf.clone()).into_inner() {
                    State::Data(b, v) => {
                        $next_self.buf    = b;

                        $on_next

                        Some(v)
                    },
                    State::Error(b, e) => {
                        $next_self.state = EndState::Error(b, e);

                        None
                    },
                    State::Incomplete(n) => {
                        $next_self.state = EndState::Incomplete(n);

                        None
                    },
                }
            }
        }
    };
    ( $iter_name:ident ( $data_ty:ty ) {
        size_hint($size_hint_self:ident) $size_hint:block
    } ) => {
        impl_iter!($iter_name ( $data_ty ) {
            size_hint ( $size_hint_self ) $size_hint

            next(self) {
                pre {}
                on  {}
            }
        })
    };
}

/// Trait for iterating a parser based on a range.
pub trait BoundedRange {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U>;
}

impl BoundedRange for Range<usize> {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(ToIter((usize, usize)) {
            size_hint(self) {
                (self.data.0, Some(self.data.1))
            }

            next(self) {
                pre {
                    if self.data.1 == 0 {
                        return None;
                    }
                }
                on {
                    self.data.0  = if self.data.0 == 0 { 0 } else { self.data.0 - 1 };
                    self.data.1 -= 1;
                }
            }
        });

        let mut iter = ToIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // Range is closed on left side, open on right, ie. [self.start, self.end)
            data:   (self.start, max(self.end, 1) - 1),
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            // Got all occurrences of the parser
            (s, (0, 0), _) => s.ret(result),
            // Ok, last parser failed and we have reached minimum, we have iterated all.
            // Return remainder of buffer and the collected result
            (s, (0, _), EndState::Error(_, _))   => s.ret(result),
            // Nested parser incomplete but reached at least minimum, propagate if not at end
            (s, (0, _), EndState::Incomplete(n)) => if s.is_last_slice() {
                s.ret(result)
            } else {
                s.incomplete(n)
            },
            // Did not reach minimum, propagate
            (s, (_, _), EndState::Error(b, e))   => s.replace(b).err(e),
            (s, (_, _), EndState::Incomplete(n)) => s.incomplete(n),
        }
    }
}

impl BoundedRange for RangeFrom<usize> {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(FromIter(usize) {
            size_hint(self) {
                (self.data, None)
            }

            next(self) {
                pre {}
                on  {
                    self.data = if self.data == 0 { 0 } else { self.data - 1 };
                }
            }
        });

        let mut iter = FromIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // Inclusive
            data:   self.start,
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            // We got at least n items
            (s, 0, EndState::Error(_, _))   => s.ret(result),
            // Nested parser incomplete, propagate if not at end
            (s, 0, EndState::Incomplete(n)) => if s.is_last_slice() {
                s.ret(result)
            } else {
                s.incomplete(n)
            },
            // Items still remaining, propagate
            (s, _, EndState::Error(b, e))   => s.replace(b).err(e),
            (s, _, EndState::Incomplete(n)) => s.incomplete(n),
        }
    }
}

impl BoundedRange for RangeFull {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(ManyIter(()) {
            size_hint(self) {
                (0, None)
            }
        });

        let mut iter = ManyIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // No data required
            data:   (),
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            (s, (), EndState::Error(_, _))   => s.ret(result),
            // Nested parser incomplete, propagate if not at end
            (s, (), EndState::Incomplete(n)) => if s.is_last_slice() {
                s.ret(result)
            } else {
                s.incomplete(n)
            },
        }
    }
}

impl BoundedRange for RangeTo<usize> {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(ToIter(usize) {
            size_hint(self) {
                (0, Some(self.data))
            }

            next(self) {
                pre {
                    if self.data == 0 {
                        return None;
                    }
                }
                on {
                    self.data  -= 1;
                }
            }
        });

        let mut iter = ToIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // Exclusive range [0, end)
            data:   max(self.end, 1) - 1,
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            // Either error or incomplete after the end
            (s, 0, _)                       => s.ret(result),
            // Inside of range, never outside
            (s, _, EndState::Error(_, _))   => s.ret(result),
            // Nested parser incomplete, propagate if not at end
            (s, _, EndState::Incomplete(n)) => if s.is_last_slice() {
                s.ret(result)
            } else {
                s.incomplete(n)
            },
        }
    }
}

impl BoundedRange for usize {
    #[inline]
    fn parse<'a, I, T, E, F, U>(&self, i: Input<'a, I>, f: F) -> ParseResult<'a, I, T, E>
      where I: Copy,
            U: 'a,
            F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
            T: FromIterator<U> {
        impl_iter!(ToIter(usize) {
            size_hint(self) {
                (self.data, Some(self.data))
            }

            next(self) {
                pre {
                    if self.data == 0 {
                        return None;
                    }
                }
                on {
                    self.data  -= 1;
                }
            }
        });

        let mut iter = ToIter {
            state:  EndState::Incomplete(1),
            parser: f,
            buf:    i,
            // Excatly self
            data:   *self,
            _t:     PhantomData,
        };

        let (result, state) = run_from_iter!(iter as T);

        match state {
            // Got exact
            (s, 0, _)                       => s.ret(result),
            // We have got too few items, propagate error
            (s, _, EndState::Error(b, e))   => s.replace(b).err(e),
            // Nested parser incomplete, propagate
            (s, _, EndState::Incomplete(n)) => s.incomplete(n),
        }
    }
}

#[inline]
pub fn many<'a, I, T, E, F, U, R>(i: Input<'a, I>, r: R, f: F) -> ParseResult<'a, I, T, E>
  where I: Copy,
        R: BoundedRange,
        U: 'a,
        F: FnMut(Input<'a, I>) -> ParseResult<'a, I, U, E>,
        T: FromIterator<U> {
    BoundedRange::parse(&r, i, f)
}
<|endoftext|>


<commit_before>use nom::{multispace, eol};

named!(pub comment <()>, chain!(
  tag!("--") ~
  take_till!(is_eol) ~
  eol,
  || ()
));

named!(pub skip_other <()>, chain!(
  multispace? ~
  comment? ~
  multispace? ~
  chain!(
     complete!(peek!(tag!("--"))) ~
     complete!(skip_other),
     || ()
  )?,
  || ()
));

pub fn is_eol(byte: u8) -> bool {
  let chr = byte as char;
  chr == '\n' || chr == '\r'
}

#[test]
fn test_comment() {
  assert_eq!(
    "".as_bytes(),
    comment("--\n".as_bytes()).unwrap().0
  );
  assert_eq!(
    "".as_bytes(),
    comment("--foo bar asdf\n".as_bytes()).unwrap().0
  );
  assert_eq!(
    "  ".as_bytes(),
    comment("--\n  ".as_bytes()).unwrap().0
  );
  assert_eq!(
    "foobar".as_bytes(),
    comment("--asdf\nfoobar".as_bytes()).unwrap().0
  );
  assert!(comment("foo --\n".as_bytes()).is_err());
  assert!(comment(" bar --\n".as_bytes()).is_err());
  assert!(comment(" -asdf-\n".as_bytes()).is_err());
  assert!(comment("-".as_bytes()).is_incomplete());
  assert!(comment("--".as_bytes()).is_incomplete());
}

#[test]
fn test_skip_other() {
  assert_eq!(
    "".as_bytes(),
    skip_other("  --\n".as_bytes()).unwrap().0
  );
  assert_eq!(
    "".as_bytes(),
    skip_other("--\n  ".as_bytes()).unwrap().0
  );
  assert_eq!(
    "".as_bytes(),
    skip_other("--\n \n ".as_bytes()).unwrap().0
  );
  assert_eq!(
    "".as_bytes(),
    skip_other("--\n -- adf\n ".as_bytes()).unwrap().0
  );
  assert!(skip_other(" -".as_bytes()).is_incomplete());
  assert!(skip_other(" --".as_bytes()).is_incomplete());
  assert!(skip_other(" --\n -".as_bytes()).is_done());
}
<commit_msg>Update skip_other parser to partially use do_parse<commit_after>use nom::{multispace, eol};

named!(pub comment <()>, chain!(
  tag!("--") ~
  take_till!(is_eol) ~
  eol,
  || ()
));

named!(pub skip_other <()>, do_parse!(
  opt!(multispace) >>
  opt!(comment) >>
  opt!(multispace) >>
  opt!(chain!(
     complete!(peek!(tag!("--"))) ~
     complete!(skip_other),
     || ()
  )) >>
  ()
));

pub fn is_eol(byte: u8) -> bool {
  let chr = byte as char;
  chr == '\n' || chr == '\r'
}

#[test]
fn test_comment() {
  assert_eq!(
    "".as_bytes(),
    comment("--\n".as_bytes()).unwrap().0
  );
  assert_eq!(
    "".as_bytes(),
    comment("--foo bar asdf\n".as_bytes()).unwrap().0
  );
  assert_eq!(
    "  ".as_bytes(),
    comment("--\n  ".as_bytes()).unwrap().0
  );
  assert_eq!(
    "foobar".as_bytes(),
    comment("--asdf\nfoobar".as_bytes()).unwrap().0
  );
  assert!(comment("foo --\n".as_bytes()).is_err());
  assert!(comment(" bar --\n".as_bytes()).is_err());
  assert!(comment(" -asdf-\n".as_bytes()).is_err());
  assert!(comment("-".as_bytes()).is_incomplete());
  assert!(comment("--".as_bytes()).is_incomplete());
}

#[test]
fn test_skip_other() {
  assert_eq!(
    "".as_bytes(),
    skip_other("  --\n".as_bytes()).unwrap().0
  );
  assert_eq!(
    "".as_bytes(),
    skip_other("--\n  ".as_bytes()).unwrap().0
  );
  assert_eq!(
    "".as_bytes(),
    skip_other("--\n \n ".as_bytes()).unwrap().0
  );
  assert_eq!(
    "".as_bytes(),
    skip_other("--\n -- adf\n ".as_bytes()).unwrap().0
  );
  assert!(skip_other(" -".as_bytes()).is_incomplete());
  assert!(skip_other(" --".as_bytes()).is_incomplete());
  assert!(skip_other(" --\n -".as_bytes()).is_done());
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A Builder type for [`Uuid`]s.
//!
//! [`Uuid`]: ../struct.Uuid.html

use prelude::*;
use BytesError;

/// A builder struct for creating a [`Uuid`]
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct Builder(Uuid);

impl Builder {
    /// Creates a `Builder` using the supplied big-endian bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Bytes;
    /// use uuid::Builder;
    ///
    /// let bytes: Bytes = [
    ///     70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63,
    ///     62,
    /// ];
    ///
    /// let builder = Builder::from_bytes_be(bytes);
    /// let uuid = builder.build().to_hyphenated().to_string();
    ///
    /// let expected_uuid = String::from("46ebd0ee-0e6d-43c9-b90d-ccc35a913f3e");
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```compile_fail
    /// use uuid::Bytes;
    /// use uuid::Builder;
    ///
    /// let bytes: Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile
    ///
    /// let uuid = Builder::from_bytes_le(bytes);
    /// ```
    pub fn from_bytes_be(b: Bytes) -> Self {
        Builder(Uuid::from_bytes_be(b))
    }

    /// Creates a `Builder` using the supplied little-endian bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Bytes;
    /// use uuid::Builder;
    ///
    /// let bytes: Bytes = [
    ///     70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63,
    ///     62,
    /// ];
    ///
    /// let builder = Builder::from_bytes_le(bytes);
    /// let uuid = builder.build().to_hyphenated().to_string();
    ///
    /// let expected_uuid = String::from("eed0eb46-6d0e-c943-b90d-ccc35a913f3e");
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```compile_fail
    /// use uuid::Bytes;
    /// use uuid::Builder;
    ///
    /// let bytes: Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile
    ///
    /// let uuid = Builder::from_bytes_le(bytes);
    /// ```
    pub fn from_bytes_le(b: Bytes) -> Self {
        Builder(Uuid::from_bytes_le(b))
    }

    /// Creates a `Builder` using the supplied big-endian bytes.
    ///
    /// # Errors
    ///
    /// This function will return an error if `b` has any length other than 16.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87];
    ///
    /// let builder = Builder::from_slice_be(&bytes);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0436430c-2b02-624c-2032-570501212b57"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```
    /// use uuid::prelude::*;
    /// use uuid::Builder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76];
    ///
    /// let builder = Builder::from_slice_be(&bytes);
    ///
    /// assert!(builder.is_err());
    /// ```
    pub fn from_slice_be(b: &[u8]) -> Result<Self, BytesError> {
        const BYTES_LEN: usize = 16;

        let len = b.len();

        if len != BYTES_LEN {
            return Err(BytesError::new(BYTES_LEN, len));
        }

        let mut bytes: Bytes = [0; 16];
        bytes.copy_from_slice(b);
        Ok(Self::from_bytes_be(bytes))
    }

    /// Creates a `Builder` using the supplied little-endian bytes.
    ///
    /// # Errors
    ///
    /// This function will return an error if `b` has any length other than 16.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87];
    ///
    /// let builder = Builder::from_slice_le(&bytes);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0c433604-022b-4c62-2032-570501212b57"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```
    /// use uuid::prelude::*;
    /// use uuid::Builder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76];
    ///
    /// let builder = Builder::from_slice_le(&bytes);
    ///
    /// assert!(builder.is_err());
    /// ```
    pub fn from_slice_le(b: &[u8]) -> Result<Self, BytesError> {
        const BYTES_LEN: usize = 16;

        let len = b.len();

        if len != BYTES_LEN {
            return Err(BytesError::new(BYTES_LEN, len));
        }

        let mut bytes: Bytes = [0; 16];
        bytes.copy_from_slice(b);
        Ok(Self::from_bytes_le(bytes))
    }

    /// Creates a `Builder` from four field values.
    ///
    /// # Errors
    ///
    /// This function will return an error if `d4`'s length is not 8 bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9];
    ///
    /// let builder = Builder::from_fields(42, 12, 5, &d4);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0000002a-000c-0005-0c03-0938362b0809"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An invalid length:
    ///
    /// ```
    /// use uuid::prelude::*;
    ///
    /// let d4 = [12];
    ///
    /// let builder = uuid::Builder::from_fields(42, 12, 5, &d4);
    ///
    /// assert!(builder.is_err());
    /// ```
    pub fn from_fields(
        d1: u32,
        d2: u16,
        d3: u16,
        d4: &[u8],
    ) -> Result<Self, BytesError> {
        Uuid::from_fields(d1, d2, d3, d4).map(|uuid| Builder(uuid))
    }

    /// Creates a `Builder` with an initial [`Uuid::nil`]
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let builder = Builder::nil();
    ///
    /// assert_eq!(
    ///     builder.build().to_hyphenated().to_string(),
    ///     "00000000-0000-0000-0000-000000000000"
    /// );
    /// ```
    pub fn nil() -> Self {
        Builder(Uuid::nil())
    }

    /// Specifies the variant of the internal [`Uuid`].
    pub fn set_variant(&mut self, v: Variant) -> &mut Self {
        self.0.set_variant(v);
        self
    }

    /// Specifies the version number of the internal [`Uuid`].
    pub fn set_version(&mut self, v: Version) -> &mut Self {
        self.0.set_version(v);
        self
    }

    /// Hands over the internal constructed [`Uuid`]
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let uuid = Builder::nil().build();
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "00000000-0000-0000-0000-000000000000"
    /// );
    /// ```
    pub fn build(&self) -> Uuid {
        self.0
    }
}
<commit_msg>take self by mut on build<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A Builder type for [`Uuid`]s.
//!
//! [`Uuid`]: ../struct.Uuid.html

use prelude::*;
use BytesError;

/// A builder struct for creating a [`Uuid`]
#[allow(missing_copy_implementations)]
#[derive(Debug)]
pub struct Builder(Uuid);

impl Builder {
    /// Creates a `Builder` using the supplied big-endian bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Bytes;
    /// use uuid::Builder;
    ///
    /// let bytes: Bytes = [
    ///     70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63,
    ///     62,
    /// ];
    ///
    /// let builder = Builder::from_bytes_be(bytes);
    /// let uuid = builder.build().to_hyphenated().to_string();
    ///
    /// let expected_uuid = String::from("46ebd0ee-0e6d-43c9-b90d-ccc35a913f3e");
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```compile_fail
    /// use uuid::Bytes;
    /// use uuid::Builder;
    ///
    /// let bytes: Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile
    ///
    /// let uuid = Builder::from_bytes_le(bytes);
    /// ```
    pub fn from_bytes_be(b: Bytes) -> Self {
        Builder(Uuid::from_bytes_be(b))
    }

    /// Creates a `Builder` using the supplied little-endian bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Bytes;
    /// use uuid::Builder;
    ///
    /// let bytes: Bytes = [
    ///     70, 235, 208, 238, 14, 109, 67, 201, 185, 13, 204, 195, 90, 145, 63,
    ///     62,
    /// ];
    ///
    /// let builder = Builder::from_bytes_le(bytes);
    /// let uuid = builder.build().to_hyphenated().to_string();
    ///
    /// let expected_uuid = String::from("eed0eb46-6d0e-c943-b90d-ccc35a913f3e");
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```compile_fail
    /// use uuid::Bytes;
    /// use uuid::Builder;
    ///
    /// let bytes: Bytes = [4, 54, 67, 12, 43, 2, 98, 76]; // doesn't compile
    ///
    /// let uuid = Builder::from_bytes_le(bytes);
    /// ```
    pub fn from_bytes_le(b: Bytes) -> Self {
        Builder(Uuid::from_bytes_le(b))
    }

    /// Creates a `Builder` using the supplied big-endian bytes.
    ///
    /// # Errors
    ///
    /// This function will return an error if `b` has any length other than 16.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87];
    ///
    /// let builder = Builder::from_slice_be(&bytes);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0436430c-2b02-624c-2032-570501212b57"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```
    /// use uuid::prelude::*;
    /// use uuid::Builder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76];
    ///
    /// let builder = Builder::from_slice_be(&bytes);
    ///
    /// assert!(builder.is_err());
    /// ```
    pub fn from_slice_be(b: &[u8]) -> Result<Self, BytesError> {
        const BYTES_LEN: usize = 16;

        let len = b.len();

        if len != BYTES_LEN {
            return Err(BytesError::new(BYTES_LEN, len));
        }

        let mut bytes: Bytes = [0; 16];
        bytes.copy_from_slice(b);
        Ok(Self::from_bytes_be(bytes))
    }

    /// Creates a `Builder` using the supplied little-endian bytes.
    ///
    /// # Errors
    ///
    /// This function will return an error if `b` has any length other than 16.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76, 32, 50, 87, 5, 1, 33, 43, 87];
    ///
    /// let builder = Builder::from_slice_le(&bytes);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0c433604-022b-4c62-2032-570501212b57"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An incorrect number of bytes:
    ///
    /// ```
    /// use uuid::prelude::*;
    /// use uuid::Builder;
    ///
    /// let bytes = [4, 54, 67, 12, 43, 2, 98, 76];
    ///
    /// let builder = Builder::from_slice_le(&bytes);
    ///
    /// assert!(builder.is_err());
    /// ```
    pub fn from_slice_le(b: &[u8]) -> Result<Self, BytesError> {
        const BYTES_LEN: usize = 16;

        let len = b.len();

        if len != BYTES_LEN {
            return Err(BytesError::new(BYTES_LEN, len));
        }

        let mut bytes: Bytes = [0; 16];
        bytes.copy_from_slice(b);
        Ok(Self::from_bytes_le(bytes))
    }

    /// Creates a `Builder` from four field values.
    ///
    /// # Errors
    ///
    /// This function will return an error if `d4`'s length is not 8 bytes.
    ///
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let d4 = [12, 3, 9, 56, 54, 43, 8, 9];
    ///
    /// let builder = Builder::from_fields(42, 12, 5, &d4);
    /// let uuid =
    ///     builder.map(|builder| builder.build().to_hyphenated().to_string());
    ///
    /// let expected_uuid =
    ///     Ok(String::from("0000002a-000c-0005-0c03-0938362b0809"));
    ///
    /// assert_eq!(expected_uuid, uuid);
    /// ```
    ///
    /// An invalid length:
    ///
    /// ```
    /// use uuid::prelude::*;
    ///
    /// let d4 = [12];
    ///
    /// let builder = uuid::Builder::from_fields(42, 12, 5, &d4);
    ///
    /// assert!(builder.is_err());
    /// ```
    pub fn from_fields(
        d1: u32,
        d2: u16,
        d3: u16,
        d4: &[u8],
    ) -> Result<Self, BytesError> {
        Uuid::from_fields(d1, d2, d3, d4).map(|uuid| Builder(uuid))
    }

    /// Creates a `Builder` with an initial [`Uuid::nil`]
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let builder = Builder::nil();
    ///
    /// assert_eq!(
    ///     builder.build().to_hyphenated().to_string(),
    ///     "00000000-0000-0000-0000-000000000000"
    /// );
    /// ```
    pub fn nil() -> Self {
        Builder(Uuid::nil())
    }

    /// Specifies the variant of the internal [`Uuid`].
    pub fn set_variant(&mut self, v: Variant) -> &mut Self {
        self.0.set_variant(v);
        self
    }

    /// Specifies the version number of the internal [`Uuid`].
    pub fn set_version(&mut self, v: Version) -> &mut Self {
        self.0.set_version(v);
        self
    }

    /// Hands over the internal constructed [`Uuid`]
    /// # Examples
    ///
    /// Basic usage:
    ///
    /// ```
    /// use uuid::Builder;
    ///
    /// let uuid = Builder::nil().build();
    ///
    /// assert_eq!(
    ///     uuid.to_hyphenated().to_string(),
    ///     "00000000-0000-0000-0000-000000000000"
    /// );
    /// ```
    pub fn build(&mut self) -> Uuid {
        self.0
    }
}
<|endoftext|>


<commit_before>//! Generate the site content.

// Standard library
use std::borrow::Cow::{Borrowed, Owned};
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

// Third party
use glob::{glob, Paths};
use pulldown_cmark as cmark;
use pulldown_cmark::{Event, Parser, Tag};
use syntect::highlighting::ThemeSet;

// First party
use crate::config::{Config, SyntaxOption};

/// Load the `Paths` for all markdown files in the specified content directory.
///
/// If the specified configuration values are wrong, we return a vector of all
/// the errors in the config as far as this is concerned.
///
/// TODO: move that validation elsewhere? Should probably extract a more general
/// site configuration validator.
fn load_markdown_paths(site_directory: &PathBuf, config: &Config) -> Result<Vec<PathBuf>, String> {
    let site = site_directory
        .to_str()
        .ok_or(format!("bad `site`: {:?}", site_directory));

    let directories = config.directories.content.to_str().ok_or(format!(
        "bad content directory: {:?}",
        config.directories.content
    ));

    let (site, directories) = match (site, directories) {
        (Err(s), Err(d)) => Err(s + "\n" + &d),
        (Err(s), Ok(_)) => Err(s),
        (Ok(_), Err(d)) => Err(d),
        (Ok(s), Ok(d)) => Ok((s, d)),
    }?;

    let content_glob = format!("{}/{}/**/*.md", site, directories);

    let paths = glob(&content_glob).map_err(|err| format!("{:?}", err))?;

    let (valid, errors): (Vec<Result<PathBuf, _>>, Vec<Result<_, String>>) = paths
        .map(|glob_result| glob_result.map_err(|err| format!("{:?}", err)))
        .partition(|path| path.is_ok());

    let errors: Vec<String> = errors.into_iter().map(|e| e.unwrap_err()).collect();
    if errors.len() == 0 {
        Ok(valid.into_iter().map(|v| v.unwrap()).collect())
    } else {
        Err(errors.join(",\n"))
    }
}

// TODO: this is an obvious candidate for a `HashMap`, so use that instead.
type LoadTuple<'a> = (&'a PathBuf, Result<String, String>);

fn load_content<'p>(paths: &'p [PathBuf]) -> Result<Vec<(&'p PathBuf, String)>, String> {
    let (contents, errs): (Vec<LoadTuple>, Vec<LoadTuple>) = paths
        .into_iter()
        .map(|path| {
            let content = std::fs::read_to_string(path).map_err(|e| format!("{:?}", e));
            (path, content)
        })
        .partition(|(_, result)| result.is_ok());

    if errs.len() == 0 {
        Ok(contents
            .into_iter()
            .map(|(path, contents)| (path, contents.unwrap()))
            .collect())
    } else {
        Err(errs
            .into_iter()
            .map(|(_path, err)| err.unwrap_err())
            .collect::<Vec<String>>()
            .join(",\n"))
    }
}

/// Load the templates associated with each taxonomy.
fn load_templates(_site_directory: &PathBuf, _config: &Config) -> Result<Paths, String> {
    unimplemented!()
}

// TODO: put this somewhere else when extracting all the parser logic below into
// its own module.
#[derive(Debug)]
enum ParseState<'s> {
    CodeBlock(&'s syntect::parsing::SyntaxReference),
    PlainTextBlock,
    NonCode,
}

impl<'s> std::default::Default for ParseState<'s> {
    fn default() -> ParseState<'s> {
        ParseState::NonCode
    }
}

enum Syntax {
    Highlight(syntect::highlighting::Theme),
    TagOnly,
    Off,
}

impl Syntax {
    fn try_from(config_syntax: &SyntaxOption) -> Result<Syntax, String> {
        match config_syntax {
            SyntaxOption::Highlight(theme) => {
                let theme_file = PathBuf::from("data").join(theme);
                let theme = ThemeSet::get_theme(theme_file).map_err(|err| format!("{:?}", err))?;
                Ok(Syntax::Highlight(theme))
            }
            SyntaxOption::TagOnly => Ok(Syntax::TagOnly),
            SyntaxOption::Off => Ok(Syntax::Off),
        }
    }
}

/// Generate content from a configuration.
pub fn build(site_directory: PathBuf) -> Result<(), String> {
    // NOTE: this is almost certainly not what we *ultimately* want here, but
    // it'll do as a starting point. There's a lot of `into_iter` and `collect`
    // happening here, which forces us to eagerly materialize a lot of these
    // collections rather than being able to deal with them in a more
    // "streaming" fashion.
    let config = Config::from_file(&PathBuf::from(&site_directory))?;
    let markdown_paths = load_markdown_paths(&site_directory, &config)?;
    let contents = load_content(&markdown_paths)?;

    let configured_syntax = Syntax::try_from(&config.options.syntax)?;

    // TODO: generate these! Best move: on build, generate a `.packdump`, since
    // that seems to be what Syntect knows how to deal with.
    let syntax_dir = PathBuf::from("data/syntaxes");
    let syntax_set =
        syntect::parsing::SyntaxSet::load_from_folder(syntax_dir).expect("can't load syntaxes");

    let parsed_content: Vec<(&PathBuf, String)> = contents
        .into_iter()
        .map(|(path, content)| {
            let parser = Parser::new_ext(&content, pulldown_cmark::Options::all()).scan(
                ParseState::default(),
                |state, event| match event {
                    Event::Start(Tag::CodeBlock(ref language)) => match state {
                        ParseState::NonCode => {
                            *state = match syntax_set.find_syntax_by_name(&language) {
                                Some(syntax) => ParseState::CodeBlock(syntax),
                                None => ParseState::PlainTextBlock,
                            };

                            // We start every code block with `<pre><code class="...">`
                            // so that we always have semantically correct HTML. However, we
                            // don't add the language class if the language isn't set.
                            let content = if language.len() > 0 {
                                Owned(format!(r#"
"#, language))
                            } else {
                                Borrowed("
")
                            };

                            Some(Event::Html(content))
                        }
                        ParseState::CodeBlock(_) | ParseState::PlainTextBlock => {
                            unreachable!("Bad event/state: {:?} with {:?}", event, state);
                        }
                    },

                    Event::End(Tag::CodeBlock(_)) => match state {
                        ParseState::CodeBlock(_) | ParseState::PlainTextBlock => {
                            *state = ParseState::NonCode;
                            Some(Event::Html(Borrowed("
")))
                        }
                        ParseState::NonCode => {
                            unreachable!("Bad event/state: {:?} with {:?}", event, state);
                        }
                    },

                    // When we are in a text block, we *may* be in a code block,
                    // so we may also need to do whatever highlighting is
                    // specified.
                    Event::Text(s) => {
                        match state {
                            ParseState::CodeBlock(syntax) => match &configured_syntax {
                                Syntax::Highlight(theme) => {
                                    let highlighted = syntect::html::highlighted_html_for_string(
                                        &s,
                                        &syntax_set,
                                        &syntax,
                                        theme,
                                    );

                                    Some(Event::Text(Owned(highlighted)))
                                }
                                Syntax::TagOnly => {
                                    // TODO: implement tag-only parsing with syntect
                                    unimplemented!()
                                }
                                Syntax::Off => Some(Event::Text(s)),
                            },
                            ParseState::PlainTextBlock => Some(Event::Text(s)),
                            ParseState::NonCode => Some(Event::Text(s)),
                        }
                    }

                    // TODO: accumulate footnote references and always put them
                    // at the end. Also, generate back-links for them, unless or
                    // until pulldown-cmark does so.
                    Event::FootnoteReference(s) => Some(Event::FootnoteReference(s)),

                    Event::Start(s) => Some(Event::Start(s)),
                    Event::End(e) => Some(Event::End(e)),
                    Event::InlineHtml(s) => Some(Event::InlineHtml(s)),
                    Event::Html(h) => Some(Event::Html(h)),
                    Event::SoftBreak => Some(Event::SoftBreak),
                    Event::HardBreak => Some(Event::HardBreak),
                },
            );

            // These numbers are derived from a brief survey of content in my
            // own website historically, including both code-heavy and
            // prose-heavy posts. It's probably worth exploring other corpora
            // to see if this is basically right.
            let length_bound_estimate = match &config.options.syntax {
                SyntaxOption::Off | SyntaxOption::TagOnly => 2,
                SyntaxOption::Highlight(_) => 8, // TODO: check other pages
            };

            let mut html = String::with_capacity(content.len() * length_bound_estimate);
            cmark::html::push_html(&mut html, parser);

            (path, html)
        })
        .collect();

    // TODO: extract this as part of the writing it out process.
    let output_dir = site_directory.join(&config.directories.output);

    if output_dir.exists() && !output_dir.is_dir() {
        return Err(format!("Output directory {:?} already exists!", output_dir));
    }

    if !output_dir.exists() {
        std::fs::create_dir(&output_dir).expect(&format!(
            "could not create output directory {:?}",
            &output_dir
        ));
    }

    for (path, content) in parsed_content {
        let file_path = path
            .file_name()
            .ok_or(format!("invalid file: {:?}", path))?;

        let dest = output_dir.join(file_path).with_extension("html");

        let mut fd = match File::create(&dest) {
            Ok(file) => file,
            Err(reason) => {
                return Err(format!(
                    "Could not open {} for write: {}",
                    dest.to_string_lossy(),
                    reason
                ));
            }
        };

        let result = write!(fd, "{}", content);
        if let Err(reason) = result {
            return Err(format!("{:?}", reason.kind()));
        }
    }

    Ok(())
}
<commit_msg>design: leave myself a note on `impl Iterator`.<commit_after>//! Generate the site content.

// Standard library
use std::borrow::Cow::{Borrowed, Owned};
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};

// Third party
use glob::{glob, Paths};
use pulldown_cmark as cmark;
use pulldown_cmark::{Event, Parser, Tag};
use syntect::highlighting::ThemeSet;

// First party
use crate::config::{Config, SyntaxOption};

/// Load the `Paths` for all markdown files in the specified content directory.
///
/// If the specified configuration values are wrong, we return a vector of all
/// the errors in the config as far as this is concerned.
///
/// TODO: move that validation elsewhere? Should probably extract a more general
/// site configuration validator.
fn load_markdown_paths(site_directory: &PathBuf, config: &Config) -> Result<Vec<PathBuf>, String> {
    let site = site_directory
        .to_str()
        .ok_or(format!("bad `site`: {:?}", site_directory));

    let directories = config.directories.content.to_str().ok_or(format!(
        "bad content directory: {:?}",
        config.directories.content
    ));

    let (site, directories) = match (site, directories) {
        (Err(s), Err(d)) => Err(s + "\n" + &d),
        (Err(s), Ok(_)) => Err(s),
        (Ok(_), Err(d)) => Err(d),
        (Ok(s), Ok(d)) => Ok((s, d)),
    }?;

    let content_glob = format!("{}/{}/**/*.md", site, directories);

    let paths = glob(&content_glob).map_err(|err| format!("{:?}", err))?;

    let (valid, errors): (Vec<Result<PathBuf, _>>, Vec<Result<_, String>>) = paths
        .map(|glob_result| glob_result.map_err(|err| format!("{:?}", err)))
        .partition(|path| path.is_ok());

    let errors: Vec<String> = errors.into_iter().map(|e| e.unwrap_err()).collect();
    if errors.len() == 0 {
        Ok(valid.into_iter().map(|v| v.unwrap()).collect())
    } else {
        Err(errors.join(",\n"))
    }
}

// TODO: this is an obvious candidate for a `HashMap`, so use that instead.
type LoadTuple<'a> = (&'a PathBuf, Result<String, String>);

// Instead of using `.collect` at the end of these, I *should* be able to use
// something like `Result<impl Iterator<HashMap<PathBuf, String>, String>`, even
// if the type isn't *quite* taht.
fn load_content<'p>(paths: &'p [PathBuf]) -> Result<Vec<(&'p PathBuf, String)>, String> {
    let (contents, errs): (Vec<LoadTuple>, Vec<LoadTuple>) = paths
        .into_iter()
        .map(|path| {
            let content = std::fs::read_to_string(path).map_err(|e| format!("{:?}", e));
            (path, content)
        })
        .partition(|(_, result)| result.is_ok());

    if errs.len() == 0 {
        Ok(contents
            .into_iter()
            .map(|(path, contents)| (path, contents.unwrap()))
            .collect())
    } else {
        Err(errs
            .into_iter()
            .map(|(_path, err)| err.unwrap_err())
            .collect::<Vec<String>>()
            .join(",\n"))
    }
}

/// Load the templates associated with each taxonomy.
fn load_templates(_site_directory: &PathBuf, _config: &Config) -> Result<Paths, String> {
    unimplemented!()
}

// TODO: put this somewhere else when extracting all the parser logic below into
// its own module.
#[derive(Debug)]
enum ParseState<'s> {
    CodeBlock(&'s syntect::parsing::SyntaxReference),
    PlainTextBlock,
    NonCode,
}

impl<'s> std::default::Default for ParseState<'s> {
    fn default() -> ParseState<'s> {
        ParseState::NonCode
    }
}

enum Syntax {
    Highlight(syntect::highlighting::Theme),
    TagOnly,
    Off,
}

impl Syntax {
    fn try_from(config_syntax: &SyntaxOption) -> Result<Syntax, String> {
        match config_syntax {
            SyntaxOption::Highlight(theme) => {
                let theme_file = PathBuf::from("data").join(theme);
                let theme = ThemeSet::get_theme(theme_file).map_err(|err| format!("{:?}", err))?;
                Ok(Syntax::Highlight(theme))
            }
            SyntaxOption::TagOnly => Ok(Syntax::TagOnly),
            SyntaxOption::Off => Ok(Syntax::Off),
        }
    }
}

/// Generate content from a configuration.
pub fn build(site_directory: PathBuf) -> Result<(), String> {
    // NOTE: this is almost certainly not what we *ultimately* want here, but
    // it'll do as a starting point. There's a lot of `into_iter` and `collect`
    // happening here, which forces us to eagerly materialize a lot of these
    // collections rather than being able to deal with them in a more
    // "streaming" fashion.
    let config = Config::from_file(&PathBuf::from(&site_directory))?;
    let markdown_paths = load_markdown_paths(&site_directory, &config)?;
    let contents = load_content(&markdown_paths)?;

    let configured_syntax = Syntax::try_from(&config.options.syntax)?;

    // TODO: generate these! Best move: on build, generate a `.packdump`, since
    // that seems to be what Syntect knows how to deal with.
    let syntax_dir = PathBuf::from("data/syntaxes");
    let syntax_set =
        syntect::parsing::SyntaxSet::load_from_folder(syntax_dir).expect("can't load syntaxes");

    let parsed_content: Vec<(&PathBuf, String)> = contents
        .into_iter()
        .map(|(path, content)| {
            let parser = Parser::new_ext(&content, pulldown_cmark::Options::all()).scan(
                ParseState::default(),
                |state, event| match event {
                    Event::Start(Tag::CodeBlock(ref language)) => match state {
                        ParseState::NonCode => {
                            *state = match syntax_set.find_syntax_by_name(&language) {
                                Some(syntax) => ParseState::CodeBlock(syntax),
                                None => ParseState::PlainTextBlock,
                            };

                            // We start every code block with `<pre><code class="...">`
                            // so that we always have semantically correct HTML. However, we
                            // don't add the language class if the language isn't set.
                            let content = if language.len() > 0 {
                                Owned(format!(r#"
"#, language))
                            } else {
                                Borrowed("
")
                            };

                            Some(Event::Html(content))
                        }
                        ParseState::CodeBlock(_) | ParseState::PlainTextBlock => {
                            unreachable!("Bad event/state: {:?} with {:?}", event, state);
                        }
                    },

                    Event::End(Tag::CodeBlock(_)) => match state {
                        ParseState::CodeBlock(_) | ParseState::PlainTextBlock => {
                            *state = ParseState::NonCode;
                            Some(Event::Html(Borrowed("
")))
                        }
                        ParseState::NonCode => {
                            unreachable!("Bad event/state: {:?} with {:?}", event, state);
                        }
                    },

                    // When we are in a text block, we *may* be in a code block,
                    // so we may also need to do whatever highlighting is
                    // specified.
                    Event::Text(s) => {
                        match state {
                            ParseState::CodeBlock(syntax) => match &configured_syntax {
                                Syntax::Highlight(theme) => {
                                    let highlighted = syntect::html::highlighted_html_for_string(
                                        &s,
                                        &syntax_set,
                                        &syntax,
                                        theme,
                                    );

                                    Some(Event::Text(Owned(highlighted)))
                                }
                                Syntax::TagOnly => {
                                    // TODO: implement tag-only parsing with syntect
                                    unimplemented!()
                                }
                                Syntax::Off => Some(Event::Text(s)),
                            },
                            ParseState::PlainTextBlock => Some(Event::Text(s)),
                            ParseState::NonCode => Some(Event::Text(s)),
                        }
                    }

                    // TODO: accumulate footnote references and always put them
                    // at the end. Also, generate back-links for them, unless or
                    // until pulldown-cmark does so.
                    Event::FootnoteReference(s) => Some(Event::FootnoteReference(s)),

                    Event::Start(s) => Some(Event::Start(s)),
                    Event::End(e) => Some(Event::End(e)),
                    Event::InlineHtml(s) => Some(Event::InlineHtml(s)),
                    Event::Html(h) => Some(Event::Html(h)),
                    Event::SoftBreak => Some(Event::SoftBreak),
                    Event::HardBreak => Some(Event::HardBreak),
                },
            );

            // These numbers are derived from a brief survey of content in my
            // own website historically, including both code-heavy and
            // prose-heavy posts. It's probably worth exploring other corpora
            // to see if this is basically right.
            let length_bound_estimate = match &config.options.syntax {
                SyntaxOption::Off | SyntaxOption::TagOnly => 2,
                SyntaxOption::Highlight(_) => 8, // TODO: check other pages
            };

            let mut html = String::with_capacity(content.len() * length_bound_estimate);
            cmark::html::push_html(&mut html, parser);

            (path, html)
        })
        .collect();

    // TODO: extract this as part of the writing it out process.
    let output_dir = site_directory.join(&config.directories.output);

    if output_dir.exists() && !output_dir.is_dir() {
        return Err(format!("Output directory {:?} already exists!", output_dir));
    }

    if !output_dir.exists() {
        std::fs::create_dir(&output_dir).expect(&format!(
            "could not create output directory {:?}",
            &output_dir
        ));
    }

    for (path, content) in parsed_content {
        let file_path = path
            .file_name()
            .ok_or(format!("invalid file: {:?}", path))?;

        let dest = output_dir.join(file_path).with_extension("html");

        let mut fd = match File::create(&dest) {
            Ok(file) => file,
            Err(reason) => {
                return Err(format!(
                    "Could not open {} for write: {}",
                    dest.to_string_lossy(),
                    reason
                ));
            }
        };

        let result = write!(fd, "{}", content);
        if let Err(reason) = result {
            return Err(format!("{:?}", reason.kind()));
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Utilities for working with sessions.
//!
//! Sessions are created per action request and should be used as the only way
//! to communicate with the server. Sessions are responsible for handling action
//! errors (when something goes wrong) or notifying the server that the action
//! finished (by sending appropriate status signal).
//!
//! They also keep track of various statistics (such as number of transferred
//! bytes, action runtime, etc.) and stop the execution if they exceed limits
//! for a particular request.

mod demand;
mod error;
mod response;
mod sink;

use std::convert::TryInto;

use log::{error, info};

use crate::action;
use crate::message;
pub use self::demand::{Demand, Header, Payload};
pub use self::error::{Error, ParseError};
use self::response::{Response, Status};
pub use self::sink::{Sink};

/// A specialized `Result` type for sessions.
pub type Result<T> = std::result::Result<T, Error>;

/// Object associating a session with particular action request.
///
/// This is just a convenience type used to avoid threading large numbers of
/// parameters through different function calls.
///
/// Note that the payload can be quite large object, so it should not be stored
/// with the session itself. The payload should be consumed as soon as the
/// request is dispatched to a particular handler and parsed to a concrete type.
pub struct Task<'s, S: Session> {
    /// A session that this task should be run on.
    pub session: &'s mut S,
    /// Serialized data of the action request.
    pub payload: Payload,
}

impl<'s, S: Session> Task<'s, S> {

    /// Executes the task with a particular action handler.
    pub fn execute<R, H>(self, handler: H) -> Result<()>
    where
        R: action::Request,
        H: FnOnce(&mut S, R) -> Result<()>,
    {
        let request = self.payload.parse()?;
        handler(self.session, request)
    }
}

/// Processes given message, handling all errors.
///
/// This function takes a message from the GRR server and interprets it as an
/// action request. It creates a new session object and dispatches the request
/// to an appropriate action handler. Once the action finishes, the function
/// will send a final status message, informing the server about a success
/// or a failure.
///
/// Note that if action execution fails, this function deals with all the errors
/// by sending appropriate information to the server (if possible), logging them
/// and failing hard if a critical error (e.g. communication failure) occurred.
pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => {
            info!("requested to execute the '{}' action", demand.action);
            demand
        }
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::from_demand(&demand);

    let result = action::dispatch(&demand.action, Task {
        session: &mut session,
        payload: demand.payload,
    });

    if let Err(ref error) = result {
        error!("failed to execute the '{}' action: {}", demand.action, error);
    };

    let status = Status {
        session_id: demand.header.session_id,
        request_id: demand.header.request_id,
        response_id: session.next_response_id,
        result: result,
    };

    let message = match status.try_into() {
        Ok(message) => message,
        Err(error) => {
            // If we cannot encode the final status message, there is nothing
            // we can do to notify the server, as status is responsible for
            // reporting errors. We can only log the error and carry on.
            error!("failed to encode status message: {}", error);
            return;
        }
    };

    message::send(message);
}

/// Abstraction for various kinds of sessions.
pub trait Session {
    /// Sends a reply to the flow that call the action.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where R: action::Response;

    /// Sends a message to a particular sink.
    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where R: action::Response;
}

/// A session type for unrequested action executions.
///
/// Certain kind of actions are executed not only when a server flow decides to
/// do so, but also upon particular kind of events (e.g. the agent's startup).
/// In such cases, when one needs to trigger action execution manually, ad-hoc
/// sessions should be used.
pub struct Adhoc;

impl Session for Adhoc {

    // TODO: Session trait should be probably split into two traits and then
    // make the actions that do not care about the `reply` method implement the
    // simpler one.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where
        R: action::Response,
    {
        error!("attempted to reply to an ad-hoc session, dropping response");
        drop(response);

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// A session type for ordinary action requests.
///
/// This is a normal session type that that is associated with some flow on the
/// server. It keeps track of the responses it sends and collects statistics
/// about network and runtime utilization to kill the action if it is needed.
pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    /// Constructs a new session for the given `demand` object.
    pub fn from_demand(demand: &Demand) -> Action {
        Action {
            header: demand.header.clone(),
            next_response_id: 0,
        }
    }

    /// Wraps an action response to a session-specific response.
    fn wrap<R>(&self, response: R) -> Response<R>
    where
        R: action::Response
    {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }
    }
}

impl Session for Action {

    fn reply<R: action::Response>(&mut self, response: R) -> Result<()> {
        send(self.wrap(response))?;
        self.next_response_id += 1;

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// Sends a session response to the server.
///
/// Note that this function is not exposed on purpose. Actions should send
/// responses through session objects which introduce a layer of safety. `send`
/// is a low-level utility supposed to be used internally.
fn send<R>(response: Response<R>) -> Result<()>
where
    R: action::Response,
{
    let message = response.try_into()?;
    message::send(message);

    Ok(())
}
<commit_msg>Add log messages for successful action executions.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Utilities for working with sessions.
//!
//! Sessions are created per action request and should be used as the only way
//! to communicate with the server. Sessions are responsible for handling action
//! errors (when something goes wrong) or notifying the server that the action
//! finished (by sending appropriate status signal).
//!
//! They also keep track of various statistics (such as number of transferred
//! bytes, action runtime, etc.) and stop the execution if they exceed limits
//! for a particular request.

mod demand;
mod error;
mod response;
mod sink;

use std::convert::TryInto;

use log::{error, info};

use crate::action;
use crate::message;
pub use self::demand::{Demand, Header, Payload};
pub use self::error::{Error, ParseError};
use self::response::{Response, Status};
pub use self::sink::{Sink};

/// A specialized `Result` type for sessions.
pub type Result<T> = std::result::Result<T, Error>;

/// Object associating a session with particular action request.
///
/// This is just a convenience type used to avoid threading large numbers of
/// parameters through different function calls.
///
/// Note that the payload can be quite large object, so it should not be stored
/// with the session itself. The payload should be consumed as soon as the
/// request is dispatched to a particular handler and parsed to a concrete type.
pub struct Task<'s, S: Session> {
    /// A session that this task should be run on.
    pub session: &'s mut S,
    /// Serialized data of the action request.
    pub payload: Payload,
}

impl<'s, S: Session> Task<'s, S> {

    /// Executes the task with a particular action handler.
    pub fn execute<R, H>(self, handler: H) -> Result<()>
    where
        R: action::Request,
        H: FnOnce(&mut S, R) -> Result<()>,
    {
        let request = self.payload.parse()?;
        handler(self.session, request)
    }
}

/// Processes given message, handling all errors.
///
/// This function takes a message from the GRR server and interprets it as an
/// action request. It creates a new session object and dispatches the request
/// to an appropriate action handler. Once the action finishes, the function
/// will send a final status message, informing the server about a success
/// or a failure.
///
/// Note that if action execution fails, this function deals with all the errors
/// by sending appropriate information to the server (if possible), logging them
/// and failing hard if a critical error (e.g. communication failure) occurred.
pub fn handle<M>(message: M)
where
    M: TryInto<Demand, Error=ParseError>,
{
    let demand = match message.try_into() {
        Ok(demand) => {
            info!("requested to execute the '{}' action", demand.action);
            demand
        }
        Err(error) => {
            error!("failed to parse the message: {}", error);
            return;
        }
    };

    let mut session = Action::from_demand(&demand);

    let result = action::dispatch(&demand.action, Task {
        session: &mut session,
        payload: demand.payload,
    });

    if let Err(ref error) = result {
        error!("failed to execute the '{}' action: {}", demand.action, error);
    } else {
        info!("finished executing the '{}' action", demand.action);
    }

    let status = Status {
        session_id: demand.header.session_id,
        request_id: demand.header.request_id,
        response_id: session.next_response_id,
        result: result,
    };

    let message = match status.try_into() {
        Ok(message) => message,
        Err(error) => {
            // If we cannot encode the final status message, there is nothing
            // we can do to notify the server, as status is responsible for
            // reporting errors. We can only log the error and carry on.
            error!("failed to encode status message: {}", error);
            return;
        }
    };

    message::send(message);
}

/// Abstraction for various kinds of sessions.
pub trait Session {
    /// Sends a reply to the flow that call the action.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where R: action::Response;

    /// Sends a message to a particular sink.
    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where R: action::Response;
}

/// A session type for unrequested action executions.
///
/// Certain kind of actions are executed not only when a server flow decides to
/// do so, but also upon particular kind of events (e.g. the agent's startup).
/// In such cases, when one needs to trigger action execution manually, ad-hoc
/// sessions should be used.
pub struct Adhoc;

impl Session for Adhoc {

    // TODO: Session trait should be probably split into two traits and then
    // make the actions that do not care about the `reply` method implement the
    // simpler one.
    fn reply<R>(&mut self, response: R) -> Result<()>
    where
        R: action::Response,
    {
        error!("attempted to reply to an ad-hoc session, dropping response");
        drop(response);

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// A session type for ordinary action requests.
///
/// This is a normal session type that that is associated with some flow on the
/// server. It keeps track of the responses it sends and collects statistics
/// about network and runtime utilization to kill the action if it is needed.
pub struct Action {
    header: Header,
    next_response_id: u64,
}

impl Action {

    /// Constructs a new session for the given `demand` object.
    pub fn from_demand(demand: &Demand) -> Action {
        Action {
            header: demand.header.clone(),
            next_response_id: 0,
        }
    }

    /// Wraps an action response to a session-specific response.
    fn wrap<R>(&self, response: R) -> Response<R>
    where
        R: action::Response
    {
        Response {
            session_id: self.header.session_id.clone(),
            request_id: Some(self.header.request_id),
            response_id: Some(self.next_response_id),
            data: response,
        }
    }
}

impl Session for Action {

    fn reply<R: action::Response>(&mut self, response: R) -> Result<()> {
        send(self.wrap(response))?;
        self.next_response_id += 1;

        Ok(())
    }

    fn send<R>(&mut self, sink: Sink, response: R) -> Result<()>
    where
        R: action::Response,
    {
        send(sink.wrap(response))?;

        Ok(())
    }
}

/// Sends a session response to the server.
///
/// Note that this function is not exposed on purpose. Actions should send
/// responses through session objects which introduce a layer of safety. `send`
/// is a low-level utility supposed to be used internally.
fn send<R>(response: Response<R>) -> Result<()>
where
    R: action::Response,
{
    let message = response.try_into()?;
    message::send(message);

    Ok(())
}
<|endoftext|>


<commit_before>use std::mem;
use super::gl;
use super::gl_lib::types::*;
use super::{Buffer, ArrayBufferBinder, ElementArrayBufferBinder};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder
        }
    }

    pub fn clear_color(&mut self, color: super::Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();
            gl::GenBuffers(1, &mut id as *mut GLuint);
            Buffer::from_id(id)
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}
<commit_msg>Add `Context.create_shader`<commit_after>use std::mem;
use super::gl;
use super::gl_lib::types::*;
use super::{Buffer, ArrayBufferBinder, ElementArrayBufferBinder};
use super::{Shader, ShaderType};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder
        }
    }

    pub fn clear_color(&mut self, color: super::Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();
            gl::GenBuffers(1, &mut id as *mut GLuint);
            Buffer::from_id(id)
        }
    }

    pub fn create_shader(&self, shader_type: ShaderType) -> Result<Shader, ()> {
        unsafe {
            let id = gl::CreateShader(shader_type as GLenum);
            if id > 0 {
                Ok(Shader::from_id(id))
            }
            else {
                Err(())
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}
<|endoftext|>