<commit_before>//! Implements iterative deepening, aspiration windows, multi-PV.
//!
//! Iterative deepening works as follows: the program starts with a
//! one ply search, then increments the search depth and does another
//! search. This process is repeated until the time allocated for the
//! search is exhausted. In case of an unfinished search, the program
//! always has the option to fall back to the move selected in the
//! last iteration of the search.
//!
//! Aspiration windows are a way to reduce the search space in the
//! search. The way it works is that we get the value from the last
//! search iteration, calculate a window around it, and use this as
//! alpha-beta bounds for the next search. Because the window is
//! narrower, more beta cutoffs are achieved, and the search takes a
//! shorter time. The drawback is that if the true score is outside
//! this window, then a costly re-search must be made. But then most
//! probably the re-search will be much faster, because many positions
//! will be remembered from the transposition table.
//!
//! In multi-PV mode the engine calculates and sends to the GUI
//! several principal variations (PV), each one starting with a
//! different first move.

use std::cmp::{min, max};
use std::mem;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use basetypes::*;
use moves::*;
use tt::*;
use position::Position;
use search::MAX_DEPTH;
use search::threading::{Command, Report, serve_simple, serve_deepening};

/// The half-with of the initial aspiration window.
const INITIAL_ASPIRATION_WINDOW: Value = 17; // 16;

/// The `SearchExecutor` trait is used to execute consecutive searches
/// in different starting positions.
pub trait SearchExecutor {
    /// Creates a new instance.
    fn new(tt: Arc<Tt>) -> Self;

    /// Starts a new search.
    ///
    /// * `search_id`: a number identifying the new search;
    ///
    /// * `position`: the root position;
    ///
    /// * `depth`: the requested search depth;
    ///
    /// * `lower_bound`: the lower bound for the new search;
    ///
    /// * `upper_bound`: the upper bound for the new search;
    ///
    /// * `value`: the evaluation of the root position so far, or
    ///   `VALUE_UNKNOWN` if not available.
    ///
    /// * `searchmoves`: restricts the analysis to the supplied list
    ///   of moves only (no restrictions if the suppied list is
    ///   empty);
    ///
    /// * `variation_count`: specifies how many best lines of play to
    ///   calculate (the first move in each line will be different).
    ///
    /// After calling `start_search`, `try_recv_report` must be called
    /// periodically until the returned report indicates that the
    /// search is done. A new search must not be started until the
    /// previous search is done.
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize);

    /// Attempts to return a search report without blocking.
    fn try_recv_report(&mut self) -> Result<Report, TryRecvError>;

    /// Requests the termination of the current search.
    ///
    /// After calling `terminate`, `try_recv_report` must continue to
    /// be called periodically until the returned report indicates
    /// that the search is done.
    fn terminate_search(&mut self);
}

/// Executes bare alpha-beta searches to a fixed depth.
pub struct SimpleSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for SimpleSearcher {
    fn new(tt: Arc<Tt>) -> SimpleSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        SimpleSearcher {
            thread: Some(thread::spawn(move || {
                serve_simple(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        debug_assert!(searchmoves.is_empty());
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for SimpleSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}

/// Executes multi-PV searches to a fixed depth.
pub struct MultipvSearcher;

/// Executes multi-PV searches to a fixed depth with aspiration.
pub struct AspirationSearcher {
    search_id: usize,
    position: Position,
    depth: u8,
    lower_bound: Value,
    upper_bound: Value,
    value: Value,
    searchmoves: Vec<Move>,
    variation_count: usize,

    /// `true` if the current search has been terminated.
    search_is_terminated: bool,

    /// The number of positions analyzed during previous (failed) searches.
    previously_searched_nodes: NodeCount,

    /// The aspiration window will be widened by this value if the
    /// search fails. (We use `isize` to avoid overflows.)
    delta: isize,

    /// The lower bound of the aspiration window.
    alpha: Value,

    /// The upper bound of the aspiration window.
    beta: Value,

    /// The real work will be handed over to `SimpleSearcher`.
    searcher: SimpleSearcher,
}

impl AspirationSearcher {
    /// A helper method. It tells `self.searcher` to run a new search.
    fn start_aspirated_search(&mut self) {
        self.searcher.start_search(0,
                                   self.position.clone(),
                                   self.depth,
                                   self.alpha,
                                   self.beta,
                                   self.value,
                                   self.searchmoves.clone(), // TODO: pass ref or Arc?
                                   self.variation_count);
    }

    /// A helper method. It multiplies `self.delta` by a constant.
    fn increase_delta(&mut self) {
        self.delta += 3 * self.delta / 8;
        if self.delta > 1500 {
            self.delta = 1_000_000;
        }
    }

    /// A helper method. It widens the aspiration window if necessary.
    fn widen_aspiration_window(&mut self) -> bool {
        let v = self.value as isize;
        if self.value <= self.alpha && self.lower_bound < self.alpha {
            // Set smaller `self.alpha`.
            self.alpha = max(v - self.delta, self.lower_bound as isize) as Value;
            self.increase_delta();
            return true;
        } else if self.value >= self.beta && self.upper_bound > self.beta {
            // Set bigger `self.beta`.
            self.beta = min(v + self.delta, self.upper_bound as isize) as Value;
            self.increase_delta();
            return true;
        }
        false
    }
}

impl SearchExecutor for AspirationSearcher {
    fn new(tt: Arc<Tt>) -> AspirationSearcher {
        let mut this: AspirationSearcher = unsafe { mem::uninitialized() };
        this.searcher = SimpleSearcher::new(tt);
        this
    }

    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.search_id = search_id;
        self.position = position;
        self.depth = depth;
        self.lower_bound = lower_bound;
        self.upper_bound = upper_bound;
        self.value = value;
        self.searchmoves = searchmoves;
        self.variation_count = variation_count;
        self.search_is_terminated = false;
        self.previously_searched_nodes = 0;
        self.delta = INITIAL_ASPIRATION_WINDOW as isize;

        // Set the initial aspiration window (`self.alpha`, `self.beta`).
        let (a, b) = if value == VALUE_UNKNOWN || value < lower_bound || value > upper_bound {
            (lower_bound, upper_bound)
        } else {
            let v = value as isize;
            (max(v - self.delta, lower_bound as isize) as Value,
             min(v + self.delta, upper_bound as isize) as Value)
        };
        self.alpha = a;
        self.beta = b;

        self.start_aspirated_search();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        let Report { searched_nodes, depth, value, best_moves, done, .. } =
            try!(self.searcher.try_recv_report());
        let searched_nodes = self.previously_searched_nodes + searched_nodes;
        let depth = if done && !self.search_is_terminated {
            self.previously_searched_nodes = searched_nodes;
            self.value = value;
            if self.widen_aspiration_window() {
                // Start a re-search.
                self.start_aspirated_search();
                return Err(TryRecvError::Empty);
            }
            depth
        } else {
            0
        };

        return Ok(Report {
            search_id: self.search_id,
            searched_nodes: searched_nodes,
            depth: depth,
            value: self.value,
            best_moves: best_moves,
            done: done,
        });
    }

    fn terminate_search(&mut self) {
        self.search_is_terminated = true;
        self.searcher.terminate_search();
    }
}

/// Executes deepeing multi-PV searches with aspiration.
pub struct DeepeningSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for DeepeningSearcher {
    fn new(tt: Arc<Tt>) -> DeepeningSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        DeepeningSearcher {
            thread: Some(thread::spawn(move || {
                serve_deepening(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for DeepeningSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}
<commit_msg>remove todo comment<commit_after>//! Implements iterative deepening, aspiration windows, multi-PV.
//!
//! Iterative deepening works as follows: the program starts with a
//! one ply search, then increments the search depth and does another
//! search. This process is repeated until the time allocated for the
//! search is exhausted. In case of an unfinished search, the program
//! always has the option to fall back to the move selected in the
//! last iteration of the search.
//!
//! Aspiration windows are a way to reduce the search space in the
//! search. The way it works is that we get the value from the last
//! search iteration, calculate a window around it, and use this as
//! alpha-beta bounds for the next search. Because the window is
//! narrower, more beta cutoffs are achieved, and the search takes a
//! shorter time. The drawback is that if the true score is outside
//! this window, then a costly re-search must be made. But then most
//! probably the re-search will be much faster, because many positions
//! will be remembered from the transposition table.
//!
//! In multi-PV mode the engine calculates and sends to the GUI
//! several principal variations (PV), each one starting with a
//! different first move.

use std::cmp::{min, max};
use std::mem;
use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use basetypes::*;
use moves::*;
use tt::*;
use position::Position;
use search::MAX_DEPTH;
use search::threading::{Command, Report, serve_simple, serve_deepening};

/// The half-with of the initial aspiration window.
const INITIAL_ASPIRATION_WINDOW: Value = 17; // 16;

/// The `SearchExecutor` trait is used to execute consecutive searches
/// in different starting positions.
pub trait SearchExecutor {
    /// Creates a new instance.
    fn new(tt: Arc<Tt>) -> Self;

    /// Starts a new search.
    ///
    /// * `search_id`: a number identifying the new search;
    ///
    /// * `position`: the root position;
    ///
    /// * `depth`: the requested search depth;
    ///
    /// * `lower_bound`: the lower bound for the new search;
    ///
    /// * `upper_bound`: the upper bound for the new search;
    ///
    /// * `value`: the evaluation of the root position so far, or
    ///   `VALUE_UNKNOWN` if not available.
    ///
    /// * `searchmoves`: restricts the analysis to the supplied list
    ///   of moves only (no restrictions if the suppied list is
    ///   empty);
    ///
    /// * `variation_count`: specifies how many best lines of play to
    ///   calculate (the first move in each line will be different).
    ///
    /// After calling `start_search`, `try_recv_report` must be called
    /// periodically until the returned report indicates that the
    /// search is done. A new search must not be started until the
    /// previous search is done.
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize);

    /// Attempts to return a search report without blocking.
    fn try_recv_report(&mut self) -> Result<Report, TryRecvError>;

    /// Requests the termination of the current search.
    ///
    /// After calling `terminate`, `try_recv_report` must continue to
    /// be called periodically until the returned report indicates
    /// that the search is done.
    fn terminate_search(&mut self);
}

/// Executes bare alpha-beta searches to a fixed depth.
pub struct SimpleSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for SimpleSearcher {
    fn new(tt: Arc<Tt>) -> SimpleSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        SimpleSearcher {
            thread: Some(thread::spawn(move || {
                serve_simple(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        debug_assert!(searchmoves.is_empty());
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for SimpleSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}

/// Executes multi-PV searches to a fixed depth.
pub struct MultipvSearcher;

/// Executes multi-PV searches to a fixed depth with aspiration.
pub struct AspirationSearcher {
    search_id: usize,
    position: Position,
    depth: u8,
    lower_bound: Value,
    upper_bound: Value,
    value: Value,
    searchmoves: Vec<Move>,
    variation_count: usize,

    /// `true` if the current search has been terminated.
    search_is_terminated: bool,

    /// The number of positions analyzed during previous (failed) searches.
    previously_searched_nodes: NodeCount,

    /// The aspiration window will be widened by this value if the
    /// search fails. (We use `isize` to avoid overflows.)
    delta: isize,

    /// The lower bound of the aspiration window.
    alpha: Value,

    /// The upper bound of the aspiration window.
    beta: Value,

    /// The real work will be handed over to `SimpleSearcher`.
    searcher: SimpleSearcher,
}

impl AspirationSearcher {
    /// A helper method. It tells `self.searcher` to run a new search.
    fn start_aspirated_search(&mut self) {
        self.searcher.start_search(0,
                                   self.position.clone(),
                                   self.depth,
                                   self.alpha,
                                   self.beta,
                                   self.value,
                                   self.searchmoves.clone(),
                                   self.variation_count);
    }

    /// A helper method. It multiplies `self.delta` by a constant.
    fn increase_delta(&mut self) {
        self.delta += 3 * self.delta / 8;
        if self.delta > 1500 {
            self.delta = 1_000_000;
        }
    }

    /// A helper method. It widens the aspiration window if necessary.
    fn widen_aspiration_window(&mut self) -> bool {
        let v = self.value as isize;
        if self.value <= self.alpha && self.lower_bound < self.alpha {
            // Set smaller `self.alpha`.
            self.alpha = max(v - self.delta, self.lower_bound as isize) as Value;
            self.increase_delta();
            return true;
        } else if self.value >= self.beta && self.upper_bound > self.beta {
            // Set bigger `self.beta`.
            self.beta = min(v + self.delta, self.upper_bound as isize) as Value;
            self.increase_delta();
            return true;
        }
        false
    }
}

impl SearchExecutor for AspirationSearcher {
    fn new(tt: Arc<Tt>) -> AspirationSearcher {
        let mut this: AspirationSearcher = unsafe { mem::uninitialized() };
        this.searcher = SimpleSearcher::new(tt);
        this
    }

    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.search_id = search_id;
        self.position = position;
        self.depth = depth;
        self.lower_bound = lower_bound;
        self.upper_bound = upper_bound;
        self.value = value;
        self.searchmoves = searchmoves;
        self.variation_count = variation_count;
        self.search_is_terminated = false;
        self.previously_searched_nodes = 0;
        self.delta = INITIAL_ASPIRATION_WINDOW as isize;

        // Set the initial aspiration window (`self.alpha`, `self.beta`).
        let (a, b) = if value == VALUE_UNKNOWN || value < lower_bound || value > upper_bound {
            (lower_bound, upper_bound)
        } else {
            let v = value as isize;
            (max(v - self.delta, lower_bound as isize) as Value,
             min(v + self.delta, upper_bound as isize) as Value)
        };
        self.alpha = a;
        self.beta = b;

        self.start_aspirated_search();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        let Report { searched_nodes, depth, value, best_moves, done, .. } =
            try!(self.searcher.try_recv_report());
        let searched_nodes = self.previously_searched_nodes + searched_nodes;
        let depth = if done && !self.search_is_terminated {
            self.previously_searched_nodes = searched_nodes;
            self.value = value;
            if self.widen_aspiration_window() {
                // Start a re-search.
                self.start_aspirated_search();
                return Err(TryRecvError::Empty);
            }
            depth
        } else {
            0
        };

        return Ok(Report {
            search_id: self.search_id,
            searched_nodes: searched_nodes,
            depth: depth,
            value: self.value,
            best_moves: best_moves,
            done: done,
        });
    }

    fn terminate_search(&mut self) {
        self.search_is_terminated = true;
        self.searcher.terminate_search();
    }
}

/// Executes deepeing multi-PV searches with aspiration.
pub struct DeepeningSearcher {
    thread: Option<thread::JoinHandle<()>>,
    thread_commands: Sender<Command>,
    thread_reports: Receiver<Report>,
}

impl SearchExecutor for DeepeningSearcher {
    fn new(tt: Arc<Tt>) -> DeepeningSearcher {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        DeepeningSearcher {
            thread: Some(thread::spawn(move || {
                serve_deepening(tt, commands_rx, reports_tx);
            })),
            thread_commands: commands_tx,
            thread_reports: reports_rx,
        }
    }

    #[allow(unused_variables)]
    fn start_search(&mut self,
                    search_id: usize,
                    position: Position,
                    depth: u8,
                    lower_bound: Value,
                    upper_bound: Value,
                    value: Value,
                    searchmoves: Vec<Move>,
                    variation_count: usize) {
        debug_assert!(depth <= MAX_DEPTH);
        debug_assert!(lower_bound < upper_bound);
        debug_assert!(lower_bound != VALUE_UNKNOWN);
        self.thread_commands
            .send(Command::Search {
                search_id: search_id,
                position: position,
                depth: depth,
                lower_bound: lower_bound,
                upper_bound: upper_bound,
            })
            .unwrap();
    }

    fn try_recv_report(&mut self) -> Result<Report, TryRecvError> {
        self.thread_reports.try_recv()
    }

    fn terminate_search(&mut self) {
        self.thread_commands.send(Command::Stop).unwrap();
    }
}

impl Drop for DeepeningSearcher {
    fn drop(&mut self) {
        self.thread_commands.send(Command::Exit).unwrap();
        self.thread.take().unwrap().join().unwrap();
    }
}
<|endoftext|>


<commit_before>export GlyphIndex, GlyphPos, Glyph;

use au = gfx::geometry;
use au::au;
use geom::point::Point2D;

/** The index of a particular glyph within a font */
struct CompressedGlyph {
    mut value : u32
}
type GlyphIndex = u32;

enum BreakTypeFlags {
    BREAK_TYPE_NONE   = 0x0,
    BREAK_TYPE_NORMAL = 0x1,
    BREAK_TYPE_HYPEN  = 0x2,
}

// TODO: make this more type-safe.

const FLAG_CHAR_IS_SPACE : u32             = 0x10000000u32;
// These two bits store a BreakTypeFlags
const FLAG_CAN_BREAK_MASK : u32            = 0x60000000u32;
const FLAG_CAN_BREAK_SHIFT : u32           = 29u32;
const FLAG_IS_SIMPLE_GLYPH : u32           = 0x80000000u32;

// glyph advance; in au's.
const GLYPH_ADVANCE_MASK : u32             = 0x0FFF0000u32;
const GLYPH_ADVANCE_SHIFT : u32            = 16;
const GLYPH_ID_MASK : u32                  = 0x0000FFFFu32;

// Non-simple glyphs (more than one glyph per char; missing glyph,
// newline, tab, large advance, or nonzero x/y offsets) may have one
// or more detailed glyphs associated with them. They are stored in a
// side array so that there is a 1:1 mapping of CompressedGlyph to
// unicode char.

// The number of detailed glyphs for this char. If the char couldn't
// be mapped to a glyph (!FLAG_NOT_MISSING), then this actually holds
// the UTF8 code point instead.
const GLYPH_COUNT_MASK : u32               = 0x00FFFF00u32;
const GLYPH_COUNT_SHIFT : u32              = 8;
// N.B. following Gecko, these are all inverted so that a lot of
// missing chars can be memset with zeros in one fell swoop.
const FLAG_NOT_MISSING : u32               = 0x00000001u32;
const FLAG_NOT_CLUSTER_START : u32         = 0x00000002u32;
const FLAG_NOT_LIGATURE_GROUP_START : u32  = 0x00000004u32;

const FLAG_CHAR_IS_TAB : u32               = 0x00000008u32;
const FLAG_CHAR_IS_NEWLINE : u32           = 0x00000010u32;
const FLAG_CHAR_IS_LOW_SURROGATE : u32     = 0x00000020u32;
const CHAR_IDENTITY_FLAGS_MASK : u32       = 0x00000038u32;

pure fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
    ((glyphId as u32) & GLYPH_ID_MASK) == glyphId
}

pure fn is_simple_advance(advance: au) -> bool {
    let unsignedAu = advance.to_int() as u32;
    (unsignedAu & (GLYPH_ADVANCE_MASK >> GLYPH_ADVANCE_SHIFT)) == unsignedAu
}

type DetailedGlyphCount = u16;

enum GlyphStoreResult<T> {
    Simple(T),
    Detailed(u32)
}

fn SimpleGlyph(index: GlyphIndex, advance: au) -> CompressedGlyph {
    assert is_simple_glyph_id(index);
    assert is_simple_advance(advance);

    let index_mask = index as u32;
    let advance_mask = (*advance as u32) << GLYPH_ADVANCE_SHIFT;

    CompressedGlyph {
        value: index_mask | advance_mask | FLAG_IS_SIMPLE_GLYPH
    }
}

fn ComplexGlyph(startsCluster: bool, startsLigature: bool, glyphCount: u16) -> CompressedGlyph {
    let mut val = FLAG_NOT_MISSING;

    if !startsCluster {
        val |= FLAG_NOT_CLUSTER_START;
    }
    if !startsLigature {
        val |= FLAG_NOT_LIGATURE_GROUP_START;
    }
    val |= (glyphCount as u32) << GLYPH_COUNT_SHIFT;

    CompressedGlyph {
        value: val
    }
}

fn MissingGlyphs(glyphCount: u16) -> CompressedGlyph {
    CompressedGlyph {
        value: (glyphCount as u32) << GLYPH_COUNT_SHIFT
    }
}

impl CompressedGlyph {
    pure fn advance() -> GlyphStoreResult<au> {
        match self.is_simple() {
            true  => Simple(au::from_int(((self.value & GLYPH_ADVANCE_MASK) >> GLYPH_ADVANCE_SHIFT) as int)),
            false => Detailed(self.glyph_count())
        }
    }

    pure fn glyph() -> GlyphStoreResult<GlyphIndex> {
        match self.is_simple() {
            true  => Simple(self.value & GLYPH_ID_MASK),
            false => Detailed(self.glyph_count())
        }
    }

    pure fn offset() -> GlyphStoreResult<Point2D<au>> {
        match self.is_simple() {
            true  => Simple(Point2D(au(0), au(0))),
            false => Detailed(self.glyph_count())
        }
    }

    // getter methods

    // TODO: some getters are still missing; add them as needed.

    // True if original char was normal (U+0020) space. Other chars may
    // map to space glyph, but this does not account for them.
    pure fn char_is_space() -> bool {
        self.has_flag(FLAG_CHAR_IS_SPACE)
    }

    pure fn char_is_tab() -> bool {
        !self.is_simple() && self.has_flag(FLAG_CHAR_IS_TAB)
    }

    pure fn char_is_newline() -> bool {
        !self.is_simple() && self.has_flag(FLAG_CHAR_IS_NEWLINE)
    }

    // TODO: make typesafe break enum
    pure fn can_break_before() -> u8 {
        ((self.value & FLAG_CAN_BREAK_MASK) >> FLAG_CAN_BREAK_SHIFT) as u8
    }

    // setter methods

    fn set_is_space() {
        self.value |= FLAG_CHAR_IS_SPACE;
    }

    fn set_is_tab() {
        assert !self.is_simple();
        self.value |= FLAG_CHAR_IS_TAB;
    }

    fn set_is_newline() {
        assert !self.is_simple();
        self.value |= FLAG_CHAR_IS_NEWLINE;
    }

    // returns whether the setting had changed.
    fn set_can_break_before(flags: u8) -> bool {
        assert flags <= 0x2;
        let mask = (flags as u32) << FLAG_CAN_BREAK_SHIFT;
        let toggle = mask ^ (self.value & FLAG_CAN_BREAK_MASK);
        self.value ^= toggle;

        toggle as bool
    }

    // helper methods

    /*priv*/ pure fn glyph_count() -> u32 {
        assert !self.is_simple();
        (self.value & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT as u32
    }

    /*priv*/ pure fn is_simple() -> bool {
        (self.value & FLAG_IS_SIMPLE_GLYPH) == self.value
    }

    /*priv*/ pure fn has_flag(flag: u32) -> bool {
        (self.value & flag) != 0
    }
}

/** The position of a glyph on the screen. */
struct GlyphPos {
    advance: Point2D<au>,
    offset: Point2D<au>,
}

fn GlyphPos(advance: Point2D<au>, offset: Point2D<au>) -> GlyphPos {
    GlyphPos {
        advance : advance,
        offset : offset,
    }
}

/** A single glyph. */
struct Glyph {
    index: u32,
    pos: GlyphPos,
}

fn Glyph(index: u32, pos: GlyphPos) -> Glyph {
    Glyph {
        index : index,
        pos : copy pos,
    }
}
<commit_msg>Implement DetailedGlyph and some storage helpers, such as the lookup table and its records.<commit_after>use au = gfx::geometry;
use au::au;
use core::cmp::{Ord, Eq};
use core::dvec::DVec;
use geom::point::Point2D;
use std::sort;
use servo_util::vec::*;

export GlyphIndex, GlyphPos, Glyph;

struct CompressedGlyph {
    mut value : u32
}

/// The index of a particular glyph within a font
type GlyphIndex = u32;

const BREAK_TYPE_NONE   : u8 = 0x0u8;
const BREAK_TYPE_NORMAL : u8 = 0x1u8;
const BREAK_TYPE_HYPEN  : u8 = 0x2u8;

// TODO: make this more type-safe.

const FLAG_CHAR_IS_SPACE : u32             = 0x10000000u32;
// These two bits store some BREAK_TYPE_* flags
const FLAG_CAN_BREAK_MASK : u32            = 0x60000000u32;
const FLAG_CAN_BREAK_SHIFT : u32           = 29;
const FLAG_IS_SIMPLE_GLYPH : u32           = 0x80000000u32;

// glyph advance; in au's.
const GLYPH_ADVANCE_MASK : u32             = 0x0FFF0000u32;
const GLYPH_ADVANCE_SHIFT : u32            = 16;
const GLYPH_ID_MASK : u32                  = 0x0000FFFFu32;

// Non-simple glyphs (more than one glyph per char; missing glyph,
// newline, tab, large advance, or nonzero x/y offsets) may have one
// or more detailed glyphs associated with them. They are stored in a
// side array so that there is a 1:1 mapping of CompressedGlyph to
// unicode char.

// The number of detailed glyphs for this char. If the char couldn't
// be mapped to a glyph (!FLAG_NOT_MISSING), then this actually holds
// the UTF8 code point instead.
const GLYPH_COUNT_MASK : u32               = 0x00FFFF00u32;
const GLYPH_COUNT_SHIFT : u32              = 8;
// N.B. following Gecko, these are all inverted so that a lot of
// missing chars can be memset with zeros in one fell swoop.
const FLAG_NOT_MISSING : u32               = 0x00000001u32;
const FLAG_NOT_CLUSTER_START : u32         = 0x00000002u32;
const FLAG_NOT_LIGATURE_GROUP_START : u32  = 0x00000004u32;

const FLAG_CHAR_IS_TAB : u32               = 0x00000008u32;
const FLAG_CHAR_IS_NEWLINE : u32           = 0x00000010u32;
const FLAG_CHAR_IS_LOW_SURROGATE : u32     = 0x00000020u32;
const CHAR_IDENTITY_FLAGS_MASK : u32       = 0x00000038u32;

pure fn is_simple_glyph_id(glyphId: GlyphIndex) -> bool {
    ((glyphId as u32) & GLYPH_ID_MASK) == glyphId
}

pure fn is_simple_advance(advance: au) -> bool {
    let unsignedAu = advance.to_int() as u32;
    (unsignedAu & (GLYPH_ADVANCE_MASK >> GLYPH_ADVANCE_SHIFT)) == unsignedAu
}

type DetailedGlyphCount = u16;

enum GlyphStoreResult<T> {
    Simple(T),
    Detailed(u32)
}

fn SimpleGlyph(index: GlyphIndex, advance: au) -> CompressedGlyph {
    assert is_simple_glyph_id(index);
    assert is_simple_advance(advance);

    let index_mask = index as u32;
    let advance_mask = (*advance as u32) << GLYPH_ADVANCE_SHIFT;

    CompressedGlyph {
        value: index_mask | advance_mask | FLAG_IS_SIMPLE_GLYPH
    }
}

fn ComplexGlyph(startsCluster: bool, startsLigature: bool, glyphCount: u16) -> CompressedGlyph {
    let mut val = FLAG_NOT_MISSING;

    if !startsCluster {
        val |= FLAG_NOT_CLUSTER_START;
    }
    if !startsLigature {
        val |= FLAG_NOT_LIGATURE_GROUP_START;
    }
    val |= (glyphCount as u32) << GLYPH_COUNT_SHIFT;

    CompressedGlyph {
        value: val
    }
}

fn MissingGlyphs(glyphCount: u16) -> CompressedGlyph {
    CompressedGlyph {
        value: (glyphCount as u32) << GLYPH_COUNT_SHIFT
    }
}

impl CompressedGlyph {
    pure fn advance() -> GlyphStoreResult<au> {
        match self.is_simple() {
            true  => Simple(au::from_int(((self.value & GLYPH_ADVANCE_MASK) >> GLYPH_ADVANCE_SHIFT) as int)),
            false => Detailed(self.glyph_count())
        }
    }

    pure fn glyph() -> GlyphStoreResult<GlyphIndex> {
        match self.is_simple() {
            true  => Simple(self.value & GLYPH_ID_MASK),
            false => Detailed(self.glyph_count())
        }
    }

    pure fn offset() -> GlyphStoreResult<Point2D<au>> {
        match self.is_simple() {
            true  => Simple(Point2D(au(0), au(0))),
            false => Detailed(self.glyph_count())
        }
    }

    // getter methods

    // TODO: some getters are still missing; add them as needed.

    // True if original char was normal (U+0020) space. Other chars may
    // map to space glyph, but this does not account for them.
    pure fn char_is_space() -> bool {
        self.has_flag(FLAG_CHAR_IS_SPACE)
    }

    pure fn char_is_tab() -> bool {
        !self.is_simple() && self.has_flag(FLAG_CHAR_IS_TAB)
    }

    pure fn char_is_newline() -> bool {
        !self.is_simple() && self.has_flag(FLAG_CHAR_IS_NEWLINE)
    }

    // TODO: make typesafe break enum
    pure fn can_break_before() -> u8 {
        ((self.value & FLAG_CAN_BREAK_MASK) >> FLAG_CAN_BREAK_SHIFT) as u8
    }

    // setter methods

    fn set_is_space() {
        self.value |= FLAG_CHAR_IS_SPACE;
    }

    fn set_is_tab() {
        assert !self.is_simple();
        self.value |= FLAG_CHAR_IS_TAB;
    }

    fn set_is_newline() {
        assert !self.is_simple();
        self.value |= FLAG_CHAR_IS_NEWLINE;
    }

    // returns whether the setting had changed.
    fn set_can_break_before(flags: u8) -> bool {
        assert flags <= 0x2;
        let mask = (flags as u32) << FLAG_CAN_BREAK_SHIFT;
        let toggle = mask ^ (self.value & FLAG_CAN_BREAK_MASK);
        self.value ^= toggle;

        toggle as bool
    }

    // helper methods

    /*priv*/ pure fn glyph_count() -> u32 {
        assert !self.is_simple();
        (self.value & GLYPH_COUNT_MASK) >> GLYPH_COUNT_SHIFT as u32
    }

    /*priv*/ pure fn is_simple() -> bool {
        (self.value & FLAG_IS_SIMPLE_GLYPH) == self.value
    }

    /*priv*/ pure fn has_flag(flag: u32) -> bool {
        (self.value & flag) != 0
    }
}

struct DetailedGlyph {
    // The GlyphIndex, or the unicode codepoint if glyph is missing.
    index: u32,
    // glyph's advance, in the text's direction (RTL or RTL)
    advance: au,
    // glyph's offset from the font's em-box (from top-left)
    offset: Point2D<au>
}

// cg = CompressedGlyph,
// dg = DetailedGlyph

struct DetailedGlyphRecord {
    // source character/CompressedGlyph offset in the TextRun
    cg_offset: u32,
    // offset into the detailed glyphs buffer
    dg_offset: uint
}

impl DetailedGlyphRecord : Ord {
    pure fn lt(other: &DetailedGlyphRecord) -> bool { self.cg_offset <  other.cg_offset }
    pure fn le(other: &DetailedGlyphRecord) -> bool { self.cg_offset <= other.cg_offset }
    pure fn ge(other: &DetailedGlyphRecord) -> bool { self.cg_offset >= other.cg_offset }
    pure fn gt(other: &DetailedGlyphRecord) -> bool { self.cg_offset >  other.cg_offset }
}

impl DetailedGlyphRecord : Eq {
    pure fn eq(other : &DetailedGlyphRecord) -> bool { self.cg_offset == other.cg_offset }
    pure fn ne(other : &DetailedGlyphRecord) -> bool { self.cg_offset != other.cg_offset }
}

// Manages the lookup table for detailed glyphs.
struct DetailedGlyphStore {
    dg_buffer: DVec<DetailedGlyph>,
    dg_lookup: DVec<DetailedGlyphRecord>,
    mut lookup_is_sorted: bool,
}

fn DetailedGlyphStore() -> DetailedGlyphStore {
    DetailedGlyphStore {
        dg_buffer: DVec(),
        dg_lookup: DVec(),
        lookup_is_sorted: false
    }
}

impl DetailedGlyphStore {
    fn add_glyphs_for_cg(cg_offset: u32, glyphs: &[DetailedGlyph]) {
        let entry = DetailedGlyphRecord {
            cg_offset: cg_offset,
            dg_offset: self.dg_buffer.len()
        };

        /*
        TODO: don't actually assert this until asserts are compiled
        in/out based on severity, debug/release, etc.

        See Rust Issue #3647, #2228, #3627 for related information.

        do self.dg_lookup.borrow |arr| {
            assert !arr.contains(entry)
        }
        */

        self.dg_lookup.push(entry);
        self.dg_buffer.push_all(glyphs);
        self.lookup_is_sorted = false;
    }

    // not pure; may perform a deferred sort.
    fn get_glyphs_for_cg(&self, cg_offset: u32, count: uint) -> &[DetailedGlyph] {
        assert count > 0 && count < self.dg_buffer.len();
        self.ensure_sorted();

        let key = DetailedGlyphRecord {
            cg_offset: cg_offset,
            dg_offset: 0 // unused
        };

        do self.dg_lookup.borrow |records : &[DetailedGlyphRecord]| {
            match records.binary_search_index(&key) {
                None => fail ~"Invalid index not found in detailed glyph lookup table!",
                Some(i) => {
                    do self.dg_buffer.borrow |glyphs : &[DetailedGlyph]| {
                        assert i + count < glyphs.len();
                        // return a view into the buffer
                        vec::view(glyphs, i, count)
                    }
                }
            }
        }
    }

    /*priv*/ fn ensure_sorted() {
        if self.lookup_is_sorted {
            return;
        }

        do self.dg_lookup.borrow_mut |arr| {
            sort::quick_sort3(arr);
        };
        self.lookup_is_sorted = true;
    }
}

// Public data structure and API for storing glyph data
struct GlyphStore {
    mut cg_buffer: ~[CompressedGlyph],
    dg_store: DetailedGlyphStore,
}

// Initializes the glyph store, but doesn't actually shape anything.
// Use the set_glyph, set_glyphs() methods to store glyph data.
// Use the get_glyph_data method to retrieve glyph data for a char..
fn GlyphStore(text: ~str) {

}

impl GlyphStore {

}

// XXX: legacy glyphs below. rip out once converted to new glyphs

/** The position of a glyph on the screen. */
struct GlyphPos {
    advance: Point2D<au>,
    offset: Point2D<au>,
}

fn GlyphPos(advance: Point2D<au>, offset: Point2D<au>) -> GlyphPos {
    GlyphPos {
        advance : advance,
        offset : offset,
    }
}

/** A single glyph. */
struct Glyph {
    index: u32,
    pos: GlyphPos,
}

fn Glyph(index: u32, pos: GlyphPos) -> Glyph {
    Glyph {
        index : index,
        pos : copy pos,
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Write;
use std::net::Shutdown;
use std::net::TcpStream;

use crate::game_object::GameObjectId;

use super::session_output::SessionOutput;
use super::sign_in::SignInState;

const LF: u8 = 10;
const CR: u8 = 13;

const MAX_INPUT_LENGTH: usize = 1024;

#[derive(Clone, Debug)]
pub enum SessionState {
    SessionClosed,
    SigningIn(SignInState),
    SignedIn,
}

pub struct Session {
    pub id: u64,
    player_id: Option<GameObjectId>,
    socket: TcpStream,
    pub state: SessionState,
}

impl Session {
    pub fn close(&mut self) -> io::Result<()> {
        self.socket.shutdown(Shutdown::Both)
    }

    pub fn new(id: u64, socket: TcpStream) -> Self {
        Self {
            id,
            player_id: None,
            socket,
            state: SessionState::SigningIn(SignInState::new()),
        }
    }

    pub fn send(&mut self, output: SessionOutput) {
        match output {
            SessionOutput::JSON(_) => {}
            SessionOutput::Str(output) => send_data(&mut self.socket, output.to_owned()),
            SessionOutput::String(output) => send_data(&mut self.socket, output),
            SessionOutput::Aggregate(outputs) => {
                for output in outputs {
                    self.send(output)
                }
            }
            SessionOutput::None => {}
        }
    }
}

fn send_data(socket: &mut TcpStream, data: String) {
    if let Err(error) = socket.write(data.as_bytes()) {
        println!("Could not send data over socket: {:?}", error);
    }
}
<commit_msg>Skip unnecessary conversion to String<commit_after>use std::io;
use std::io::Write;
use std::net::Shutdown;
use std::net::TcpStream;

use crate::game_object::GameObjectId;

use super::session_output::SessionOutput;
use super::sign_in::SignInState;

const LF: u8 = 10;
const CR: u8 = 13;

const MAX_INPUT_LENGTH: usize = 1024;

#[derive(Clone, Debug)]
pub enum SessionState {
    SessionClosed,
    SigningIn(SignInState),
    SignedIn,
}

pub struct Session {
    pub id: u64,
    player_id: Option<GameObjectId>,
    socket: TcpStream,
    pub state: SessionState,
}

impl Session {
    pub fn close(&mut self) -> io::Result<()> {
        self.socket.shutdown(Shutdown::Both)
    }

    pub fn new(id: u64, socket: TcpStream) -> Self {
        Self {
            id,
            player_id: None,
            socket,
            state: SessionState::SigningIn(SignInState::new()),
        }
    }

    pub fn send(&mut self, output: SessionOutput) {
        match output {
            SessionOutput::JSON(_) => {}
            SessionOutput::Str(output) => send_data(&mut self.socket, output.as_bytes()),
            SessionOutput::String(output) => send_data(&mut self.socket, output.as_bytes()),
            SessionOutput::Aggregate(outputs) => {
                for output in outputs {
                    self.send(output)
                }
            }
            SessionOutput::None => {}
        }
    }
}

fn send_data(socket: &mut TcpStream, data: &[u8]) {
    if let Err(error) = socket.write(data) {
        println!("Could not send data over socket: {:?}", error);
    }
}
<|endoftext|>


<commit_before>use std::net::{TcpListener, ToSocketAddrs};
use std::thread;
use std::collections::HashMap;
use std;
use serde_rosmsg::to_vec;
use super::error::{ErrorKind, Result, ResultExt};
use super::header;
use super::Message;
use super::util::streamfork::{fork, TargetList, DataStream};
use super::util::tcpconnection;

pub struct Publisher {
    subscriptions: DataStream,
    pub port: u16,
    pub msg_type: String,
    pub topic: String,
    _raii: tcpconnection::Raii,
}

fn read_request<T: Message, U: std::io::Read>(mut stream: &mut U, topic: &str) -> Result<()> {
    let fields = header::decode(&mut stream)?;
    header::match_field(&fields, "md5sum", &T::md5sum())?;
    header::match_field(&fields, "type", &T::msg_type())?;
    header::match_field(&fields, "message_definition", &T::msg_definition())?;
    header::match_field(&fields, "topic", topic)?;
    if fields.get("callerid").is_none() {
        bail!(ErrorKind::HeaderMissingField("callerid".into()));
    }
    Ok(())
}

fn write_response<T: Message, U: std::io::Write>(mut stream: &mut U) -> Result<()> {
    let mut fields = HashMap::<String, String>::new();
    fields.insert(String::from("md5sum"), T::md5sum());
    fields.insert(String::from("type"), T::msg_type());
    header::encode(&mut stream, &fields)?;
    Ok(())
}

fn exchange_headers<T, U>(mut stream: &mut U, topic: &str) -> Result<()>
    where T: Message,
          U: std::io::Write + std::io::Read
{
    read_request::<T, U>(&mut stream, &topic)?;
    write_response::<T, U>(&mut stream)
}

fn listen_for_subscribers<T, U, V>(topic: &str, listener: V, targets: TargetList<U>)
    where T: Message,
          U: std::io::Read + std::io::Write + Send,
          V: Iterator<Item = U>
{
    // This listener stream never breaks by itself since it's a TcpListener
    for mut stream in listener {
        let result = exchange_headers::<T, _>(&mut stream, topic)
            .chain_err(|| ErrorKind::TopicConnectionFail(topic.into()));
        if let Err(err) = result {
            let info = err.iter()
                .map(|v| format!("{}", v))
                .collect::<Vec<_>>()
                .join("\nCaused by:");
            error!("{}", info);
            continue;
        }
        if targets.add(stream).is_err() {
            // The TCP listener gets shut down when streamfork's thread deallocates.
            // This happens only when all the corresponding publisher streams get deallocated,
            // causing streamfork's data channel to shut down
            break;
        }
    }
}

impl Publisher {
    pub fn new<T, U>(address: U, topic: &str) -> Result<Publisher>
        where T: Message,
              U: ToSocketAddrs
    {
        let listener = TcpListener::bind(address)?;
        let socket_address = listener.local_addr()?;
        let (raii, listener) = tcpconnection::iterate(listener, format!("topic '{}'", topic));
        Ok(Publisher::wrap_stream::<T, _, _>(topic, raii, listener, socket_address.port()))
    }

    fn wrap_stream<T, U, V>(topic: &str,
                            raii: tcpconnection::Raii,
                            listener: V,
                            port: u16)
                            -> Publisher
        where T: Message,
              U: std::io::Read + std::io::Write + Send + 'static,
              V: Iterator<Item = U> + Send + 'static
    {
        let (targets, data) = fork();
        let topic_name = String::from(topic);
        thread::spawn(move || listen_for_subscribers::<T, _, _>(&topic_name, listener, targets));
        Publisher {
            subscriptions: data,
            port: port,
            msg_type: T::msg_type(),
            topic: String::from(topic),
            _raii: raii,
        }
    }

    pub fn stream<T: Message>(&self) -> Result<PublisherStream<T>> {
        PublisherStream::new(self)
    }
}

// TODO: publisher should only be removed from master API once the publisher and all
// publisher streams are gone. This should be done with a RAII Arc, residing next todo
// the datastream. So maybe replace DataStream with a wrapper that holds that Arc too

pub struct PublisherStream<T: Message> {
    stream: DataStream,
    datatype: std::marker::PhantomData<T>,
}

impl<T: Message> PublisherStream<T> {
    fn new(publisher: &Publisher) -> Result<PublisherStream<T>> {
        let msg_type = T::msg_type();
        if publisher.msg_type != msg_type {
            bail!(ErrorKind::MessageTypeMismatch(publisher.msg_type.clone(), msg_type));
        }
        Ok(PublisherStream {
               stream: publisher.subscriptions.clone(),
               datatype: std::marker::PhantomData,
           })
    }

    pub fn send(&mut self, message: T) -> Result<()> {
        let bytes = to_vec(&message)?;
        // Subscriptions can only be closed from the Publisher side
        // There is no way for the streamfork thread to fail by itself
        self.stream.send(bytes).expect("Connected thread died");
        Ok(())
    }
}
<commit_msg>Don't check message definition matching<commit_after>use std::net::{TcpListener, ToSocketAddrs};
use std::thread;
use std::collections::HashMap;
use std;
use serde_rosmsg::to_vec;
use super::error::{ErrorKind, Result, ResultExt};
use super::header;
use super::Message;
use super::util::streamfork::{fork, TargetList, DataStream};
use super::util::tcpconnection;

pub struct Publisher {
    subscriptions: DataStream,
    pub port: u16,
    pub msg_type: String,
    pub topic: String,
    _raii: tcpconnection::Raii,
}

fn read_request<T: Message, U: std::io::Read>(mut stream: &mut U, topic: &str) -> Result<()> {
    let fields = header::decode(&mut stream)?;
    header::match_field(&fields, "md5sum", &T::md5sum())?;
    header::match_field(&fields, "type", &T::msg_type())?;
    header::match_field(&fields, "topic", topic)?;
    if fields.get("message_definition").is_none() {
        bail!(ErrorKind::HeaderMissingField("message_definition".into()));
    }
    if fields.get("callerid").is_none() {
        bail!(ErrorKind::HeaderMissingField("callerid".into()));
    }
    Ok(())
}

fn write_response<T: Message, U: std::io::Write>(mut stream: &mut U) -> Result<()> {
    let mut fields = HashMap::<String, String>::new();
    fields.insert(String::from("md5sum"), T::md5sum());
    fields.insert(String::from("type"), T::msg_type());
    header::encode(&mut stream, &fields)?;
    Ok(())
}

fn exchange_headers<T, U>(mut stream: &mut U, topic: &str) -> Result<()>
    where T: Message,
          U: std::io::Write + std::io::Read
{
    read_request::<T, U>(&mut stream, &topic)?;
    write_response::<T, U>(&mut stream)
}

fn listen_for_subscribers<T, U, V>(topic: &str, listener: V, targets: TargetList<U>)
    where T: Message,
          U: std::io::Read + std::io::Write + Send,
          V: Iterator<Item = U>
{
    // This listener stream never breaks by itself since it's a TcpListener
    for mut stream in listener {
        let result = exchange_headers::<T, _>(&mut stream, topic)
            .chain_err(|| ErrorKind::TopicConnectionFail(topic.into()));
        if let Err(err) = result {
            let info = err.iter()
                .map(|v| format!("{}", v))
                .collect::<Vec<_>>()
                .join("\nCaused by:");
            error!("{}", info);
            continue;
        }
        if targets.add(stream).is_err() {
            // The TCP listener gets shut down when streamfork's thread deallocates.
            // This happens only when all the corresponding publisher streams get deallocated,
            // causing streamfork's data channel to shut down
            break;
        }
    }
}

impl Publisher {
    pub fn new<T, U>(address: U, topic: &str) -> Result<Publisher>
        where T: Message,
              U: ToSocketAddrs
    {
        let listener = TcpListener::bind(address)?;
        let socket_address = listener.local_addr()?;
        let (raii, listener) = tcpconnection::iterate(listener, format!("topic '{}'", topic));
        Ok(Publisher::wrap_stream::<T, _, _>(topic, raii, listener, socket_address.port()))
    }

    fn wrap_stream<T, U, V>(topic: &str,
                            raii: tcpconnection::Raii,
                            listener: V,
                            port: u16)
                            -> Publisher
        where T: Message,
              U: std::io::Read + std::io::Write + Send + 'static,
              V: Iterator<Item = U> + Send + 'static
    {
        let (targets, data) = fork();
        let topic_name = String::from(topic);
        thread::spawn(move || listen_for_subscribers::<T, _, _>(&topic_name, listener, targets));
        Publisher {
            subscriptions: data,
            port: port,
            msg_type: T::msg_type(),
            topic: String::from(topic),
            _raii: raii,
        }
    }

    pub fn stream<T: Message>(&self) -> Result<PublisherStream<T>> {
        PublisherStream::new(self)
    }
}

// TODO: publisher should only be removed from master API once the publisher and all
// publisher streams are gone. This should be done with a RAII Arc, residing next todo
// the datastream. So maybe replace DataStream with a wrapper that holds that Arc too

pub struct PublisherStream<T: Message> {
    stream: DataStream,
    datatype: std::marker::PhantomData<T>,
}

impl<T: Message> PublisherStream<T> {
    fn new(publisher: &Publisher) -> Result<PublisherStream<T>> {
        let msg_type = T::msg_type();
        if publisher.msg_type != msg_type {
            bail!(ErrorKind::MessageTypeMismatch(publisher.msg_type.clone(), msg_type));
        }
        Ok(PublisherStream {
               stream: publisher.subscriptions.clone(),
               datatype: std::marker::PhantomData,
           })
    }

    pub fn send(&mut self, message: T) -> Result<()> {
        let bytes = to_vec(&message)?;
        // Subscriptions can only be closed from the Publisher side
        // There is no way for the streamfork thread to fail by itself
        self.stream.send(bytes).expect("Connected thread died");
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::sync::mpsc;
use specs;

#[derive(Clone, Debug)]
pub struct InputState {
  pub distance: f32,
  pub x_pos: f32,
  pub y_pos: f32,
}

impl InputState {
  pub fn new() -> InputState {
    InputState {
      distance: 1000.0,
      x_pos: 0.0,
      y_pos: 0.0,
    }
  }
}

impl specs::Component for InputState {
  type Storage = specs::HashMapStorage<InputState>;
}

#[derive(Debug)]
pub enum TerrainControl {
  ZoomOut,
  ZoomIn,
  ZoomStop,
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct TerrainControlSystem {
  queue: mpsc::Receiver<TerrainControl>,
  zoom_level: Option<f32>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl TerrainControlSystem {
  pub fn new() -> (TerrainControlSystem, mpsc::Sender<TerrainControl>) {
    let (tx, rx) = mpsc::channel();
    (TerrainControlSystem {
      queue: rx,
      zoom_level: None,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<C> specs::System<C> for TerrainControlSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;

    let mut map_input = arg.fetch(|w| w.write::<InputState>());
    while let Ok(control) = self.queue.try_recv() {
      match control {
        TerrainControl::ZoomIn => self.zoom_level = Some(2.0),
        TerrainControl::ZoomOut => self.zoom_level = Some(-2.0),
        TerrainControl::ZoomStop => self.zoom_level = None,
        TerrainControl::Up => self.y_move = Some(1.0),
        TerrainControl::Down => self.y_move = Some(-1.0),
        TerrainControl::YMoveStop => self.y_move = None,
        TerrainControl::Right => self.x_move = Some(1.0),
        TerrainControl::Left => self.x_move = Some(-1.0),
        TerrainControl::XMoveStop => self.x_move = None,
      }
    }
    if let Some(zoom) = self.zoom_level {
      for m in (&mut map_input).join() {
        m.distance += zoom;
      }
    }
    if let Some(x) = self.x_move {
      for m in (&mut map_input).join() {
        m.x_pos += x;
      }
    }
    if let Some(y) = self.y_move {
      for m in (&mut map_input).join() {
        m.y_pos += y;
      }
    }
  }
}
<commit_msg>Invert up/down keys<commit_after>use std::sync::mpsc;
use specs;

#[derive(Clone, Debug)]
pub struct InputState {
  pub distance: f32,
  pub x_pos: f32,
  pub y_pos: f32,
}

impl InputState {
  pub fn new() -> InputState {
    InputState {
      distance: 1000.0,
      x_pos: 0.0,
      y_pos: 0.0,
    }
  }
}

impl specs::Component for InputState {
  type Storage = specs::HashMapStorage<InputState>;
}

#[derive(Debug)]
pub enum TerrainControl {
  ZoomOut,
  ZoomIn,
  ZoomStop,
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct TerrainControlSystem {
  queue: mpsc::Receiver<TerrainControl>,
  zoom_level: Option<f32>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl TerrainControlSystem {
  pub fn new() -> (TerrainControlSystem, mpsc::Sender<TerrainControl>) {
    let (tx, rx) = mpsc::channel();
    (TerrainControlSystem {
      queue: rx,
      zoom_level: None,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<C> specs::System<C> for TerrainControlSystem {
  fn run(&mut self, arg: specs::RunArg, _: C) {
    use specs::Join;

    let mut map_input = arg.fetch(|w| w.write::<InputState>());
    while let Ok(control) = self.queue.try_recv() {
      match control {
        TerrainControl::ZoomIn => self.zoom_level = Some(2.0),
        TerrainControl::ZoomOut => self.zoom_level = Some(-2.0),
        TerrainControl::ZoomStop => self.zoom_level = None,
        TerrainControl::Up => self.y_move = Some(-1.0),
        TerrainControl::Down => self.y_move = Some(1.0),
        TerrainControl::YMoveStop => self.y_move = None,
        TerrainControl::Right => self.x_move = Some(1.0),
        TerrainControl::Left => self.x_move = Some(-1.0),
        TerrainControl::XMoveStop => self.x_move = None,
      }
    }
    if let Some(zoom) = self.zoom_level {
      for m in (&mut map_input).join() {
        m.distance += zoom;
      }
    }
    if let Some(x) = self.x_move {
      for m in (&mut map_input).join() {
        m.x_pos += x;
      }
    }
    if let Some(y) = self.y_move {
      for m in (&mut map_input).join() {
        m.y_pos += y;
      }
    }
  }
}
<|endoftext|>


<commit_before>use std::fmt::Debug; // Trait to bound with.

#[derive(Debug)]
struct Ref<'a, T: 'a>(&'a T);
// `Ref` contains a reference to a generic type `T` that has
// an unknown lifetime `'a`. `T` is bounded such that any
// *references* in `T` must outlive `'a`. Additionally, the lifetime
// of `Ref` may not exceed `'a`.

// A generic function which prints using the `Debug` trait.
fn print<T>(t: T) where
    T: Debug {
    println!("`print`: t is {:?}", t);
}

// Here a reference to `T` is taken where `T` implements
// `Debug` and all *references* in `T` outlive `'a`. In
// addition, `'a` must outlive the function.
fn print_ref<'a, T>(t: &'a T) where
    T: Debug + 'a {
    println!("`print_ref`: t is {:?}", t);
}

fn main() {
    let x = 7;
    let ref_x = Ref(&x);

    print(ref_x);
    print_ref(&ref_x);
}
<commit_msg>Reverted change<commit_after>use std::fmt::Debug; // Trait to bound with.

#[derive(Debug)]
struct Ref<'a, T: 'a>(&'a T);
// `Ref` contains a reference to a generic type `T` that has
// an unknown lifetime `'a`. `T` is bounded such that any
// *references* in `T` must outlive `'a`. Additionally, the lifetime
// of `Ref` may not exceed `'a`.

// A generic function which prints using the `Debug` trait.
fn print<T>(t: T) where
    T: Debug {
    println!("`print`: t is {:?}", t);
}

// Here a reference to `T` is taken where `T` implements
// `Debug` and all *references* in `T` outlive `'a`. In
// addition, `'a` must outlive the function.
fn print_ref<'a, T>(t: &'a T) where
    T: Debug + 'a {
    println!("`print_ref`: t is {:?}", t);
}

fn main() {
    let x = 7;
    let ref_x = Ref(&x);

    print_ref(&ref_x);
    print(ref_x);
}
<|endoftext|>


<commit_before>
extern crate gitlab_api as gitlab;

use std::env;
use gitlab::GitLab;
use gitlab::Pagination;

fn main() {
    let hostname = match env::var("GITLAB_HOSTNAME") {
        Ok(val) => val,
        Err(_) => {
            let default = String::from("gitlab.com");
            println!("Please set environment variable 'GITLAB_HOSTNAME'. Using default '{}'.",
                     default);
            default
        }
    };

    let token = match env::var("GITLAB_TOKEN") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set environment variable 'GITLAB_TOKEN'. Take it from \
                    http://{}/profile/account",
                   hostname);
        }
    };

    let mut gl = GitLab::new_https(&hostname, &token);
    // for i in 1..82 {
    //     gl.set_pagination(Pagination{page: i, per_page: 1});
    //     println!("projects: {:?}", gl.projects().unwrap());
    // }
    // gl.set_pagination(Pagination {
    //     page: 1,
    //     per_page: 100,
    // });
    let projects = gl.projects(gitlab::projects::Listing::new()).unwrap();
    println!("projects: {:?}", projects);
    // FIXME: Project's members are private
    // for project in projects {
    //     println!("{:?}", project.path_with_namespace);
    // }

    let projects = gl.projects_all(gitlab::projects::all::Listing::new()).unwrap();
    println!("projects: {:?}", projects);

    let listing = gitlab::projects::id::Listing::new(gitlab::projects::id::ListingId::Id(10));
    let projects = gl.projects_id(listing).unwrap();
    println!("projects: {:?}", projects);
}
<commit_msg>Use `gitlab::projects`<commit_after>
extern crate gitlab_api as gitlab;

use std::env;
use gitlab::GitLab;
use gitlab::Pagination;
use gitlab::projects;

fn main() {
    let hostname = match env::var("GITLAB_HOSTNAME") {
        Ok(val) => val,
        Err(_) => {
            let default = String::from("gitlab.com");
            println!("Please set environment variable 'GITLAB_HOSTNAME'. Using default '{}'.",
                     default);
            default
        }
    };

    let token = match env::var("GITLAB_TOKEN") {
        Ok(val) => val,
        Err(_) => {
            panic!("Please set environment variable 'GITLAB_TOKEN'. Take it from \
                    http://{}/profile/account",
                   hostname);
        }
    };

    let mut gl = GitLab::new_https(&hostname, &token);
    // for i in 1..82 {
    //     gl.set_pagination(Pagination{page: i, per_page: 1});
    //     println!("projects: {:?}", gl.projects().unwrap());
    // }
    // gl.set_pagination(Pagination {
    //     page: 1,
    //     per_page: 100,
    // });
    let projects = gl.projects(projects::Listing::new()).unwrap();
    println!("projects: {:?}", projects);
    // FIXME: Project's members are private
    // for project in projects {
    //     println!("{:?}", project.path_with_namespace);
    // }

    let projects = gl.projects_all(projects::all::Listing::new()).unwrap();
    println!("projects: {:?}", projects);

    let listing = projects::id::Listing::new(projects::id::ListingId::Id(10));
    let projects = gl.projects_id(listing).unwrap();
    println!("projects: {:?}", projects);
}
<|endoftext|>


<commit_before>extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate getopts;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate varlink;

use org_example_more::*;
use std::env;
use std::process::exit;
use std::{thread, time};
use varlink::VarlinkService;

// Dynamically build the varlink rust code.
mod org_example_more;

#[cfg(test)]
mod test;

// Main

fn print_usage(program: &str, opts: getopts::Options) {
    let brief = format!("Usage: {} [--varlink=<address>] [--client]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();

    let mut opts = getopts::Options::new();
    opts.optopt("", "varlink", "varlink address URL", "<address>");
    opts.optflag("", "client", "run in client mode");
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("", "timeout", "server timeout", "<seconds>");
    opts.optopt("", "sleep", "sleep duration", "<seconds>");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            eprintln!("{}", f.to_string());
            print_usage(&program, opts);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let client_mode = matches.opt_present("client");

    let timeout = matches
        .opt_str("timeout")
        .unwrap_or("0".to_string())
        .parse::<u64>()
        .unwrap_or(0);

    let sleep = matches
        .opt_str("sleep")
        .unwrap_or("1000".to_string())
        .parse::<u64>()
        .unwrap_or(1000);

    let address = match matches.opt_str("varlink") {
        None => {
            if !client_mode {
                eprintln!("Need varlink address in server mode.");
                print_usage(&program, opts);
                return;
            }
            format!("exec:{}", program)
        }
        Some(a) => a,
    };

    let ret = match client_mode {
        true => run_client(address),
        false => run_server(address, timeout, sleep).map_err(|e| e.into()),
    };

    exit(match ret {
        Ok(_) => 0,
        Err(err) => {
            eprintln!("error: {:?}", err);
            1
        }
    });
}

// Client

fn run_client(address: String) -> Result<()> {
    let con1 = varlink::Connection::new(&address)?;
    let new_addr;
    {
        let conn = con1.read().unwrap();
        new_addr = conn.address();
    }
    let mut iface = org_example_more::VarlinkClient::new(con1);

    let con2 = varlink::Connection::new(&new_addr)?;
    let mut pingiface = org_example_more::VarlinkClient::new(con2);

    for reply in iface.test_more(10).more()? {
        let reply = reply?;
        //assert!(reply.state.is_some());
        let state = reply.state;
        match state {
            State {
                start: Some(true),
                end: None,
                progress: None,
                ..
            } => {
                eprintln!("--- Start ---");
            }
            State {
                start: None,
                end: Some(true),
                progress: None,
                ..
            } => {
                eprintln!("--- End ---");
            }
            State {
                start: None,
                end: None,
                progress: Some(progress),
                ..
            } => {
                eprintln!("Progress: {}", progress);
                if progress > 50 {
                    let reply = pingiface.ping("Test".into()).call()?;
                    println!("Pong: '{}'", reply.pong);
                }
            }
            _ => eprintln!("Got unknown state: {:?}", state),
        }
    }

    Ok(())
}

// Server

struct MyOrgExampleMore {
    sleep_duration: u64,
}

impl VarlinkInterface for MyOrgExampleMore {
    fn ping(&self, call: &mut Call_Ping, ping: String) -> varlink::Result<()> {
        return call.reply(ping);
    }

    fn stop_serving(&self, call: &mut Call_StopServing) -> varlink::Result<()> {
        call.reply()?;
        Err(varlink::ErrorKind::ConnectionClosed.into())
    }
    fn test_more(&self, call: &mut Call_TestMore, n: i64) -> varlink::Result<()> {
        if !call.wants_more() {
            return call.reply_test_more_error("called without more".into());
        }

        if n == 0 {
            return call.reply_test_more_error("n == 0".into());
        }

        call.set_continues(true);

        call.reply(State {
            start: Some(true),
            end: None,
            progress: None,
        })?;

        for i in 0..n {
            thread::sleep(time::Duration::from_millis(self.sleep_duration));
            call.reply(State {
                progress: Some(i * 100 / n),
                start: None,
                end: None,
            })?;
        }

        call.reply(State {
            progress: Some(100),
            start: None,
            end: None,
        })?;

        call.set_continues(false);

        call.reply(State {
            end: Some(true),
            progress: None,
            start: None,
        })
    }
}

fn run_server(address: String, timeout: u64, sleep_duration: u64) -> varlink::Result<()> {
    let myexamplemore = MyOrgExampleMore { sleep_duration };
    let myinterface = org_example_more::new(Box::new(myexamplemore));
    let service = VarlinkService::new(
        "org.varlink",
        "test service",
        "0.1",
        "http://varlink.org",
        vec![Box::new(myinterface)],
    );
    varlink::listen(service, &address, 10, timeout)?;
    Ok(())
}
<commit_msg>more: fixed argument hint<commit_after>extern crate failure;
#[macro_use]
extern crate failure_derive;
extern crate getopts;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate varlink;

use org_example_more::*;
use std::env;
use std::process::exit;
use std::{thread, time};
use varlink::VarlinkService;

// Dynamically build the varlink rust code.
mod org_example_more;

#[cfg(test)]
mod test;

// Main

fn print_usage(program: &str, opts: getopts::Options) {
    let brief = format!("Usage: {} [--varlink=<address>] [--client]", program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let program = args[0].clone();

    let mut opts = getopts::Options::new();
    opts.optopt("", "varlink", "varlink address URL", "<address>");
    opts.optflag("", "client", "run in client mode");
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("", "timeout", "server timeout", "<seconds>");
    opts.optopt("", "sleep", "sleep duration", "<milliseconds>");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => {
            eprintln!("{}", f.to_string());
            print_usage(&program, opts);
            return;
        }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let client_mode = matches.opt_present("client");

    let timeout = matches
        .opt_str("timeout")
        .unwrap_or("0".to_string())
        .parse::<u64>()
        .unwrap_or(0);

    let sleep = matches
        .opt_str("sleep")
        .unwrap_or("1000".to_string())
        .parse::<u64>()
        .unwrap_or(1000);

    let address = match matches.opt_str("varlink") {
        None => {
            if !client_mode {
                eprintln!("Need varlink address in server mode.");
                print_usage(&program, opts);
                return;
            }
            format!("exec:{}", program)
        }
        Some(a) => a,
    };

    let ret = match client_mode {
        true => run_client(address),
        false => run_server(address, timeout, sleep).map_err(|e| e.into()),
    };

    exit(match ret {
        Ok(_) => 0,
        Err(err) => {
            eprintln!("error: {:?}", err);
            1
        }
    });
}

// Client

fn run_client(address: String) -> Result<()> {
    let con1 = varlink::Connection::new(&address)?;
    let new_addr;
    {
        let conn = con1.read().unwrap();
        new_addr = conn.address();
    }
    let mut iface = org_example_more::VarlinkClient::new(con1);

    let con2 = varlink::Connection::new(&new_addr)?;
    let mut pingiface = org_example_more::VarlinkClient::new(con2);

    for reply in iface.test_more(10).more()? {
        let reply = reply?;
        //assert!(reply.state.is_some());
        let state = reply.state;
        match state {
            State {
                start: Some(true),
                end: None,
                progress: None,
                ..
            } => {
                eprintln!("--- Start ---");
            }
            State {
                start: None,
                end: Some(true),
                progress: None,
                ..
            } => {
                eprintln!("--- End ---");
            }
            State {
                start: None,
                end: None,
                progress: Some(progress),
                ..
            } => {
                eprintln!("Progress: {}", progress);
                if progress > 50 {
                    let reply = pingiface.ping("Test".into()).call()?;
                    println!("Pong: '{}'", reply.pong);
                }
            }
            _ => eprintln!("Got unknown state: {:?}", state),
        }
    }

    Ok(())
}

// Server

struct MyOrgExampleMore {
    sleep_duration: u64,
}

impl VarlinkInterface for MyOrgExampleMore {
    fn ping(&self, call: &mut Call_Ping, ping: String) -> varlink::Result<()> {
        return call.reply(ping);
    }

    fn stop_serving(&self, call: &mut Call_StopServing) -> varlink::Result<()> {
        call.reply()?;
        Err(varlink::ErrorKind::ConnectionClosed.into())
    }
    fn test_more(&self, call: &mut Call_TestMore, n: i64) -> varlink::Result<()> {
        if !call.wants_more() {
            return call.reply_test_more_error("called without more".into());
        }

        if n == 0 {
            return call.reply_test_more_error("n == 0".into());
        }

        call.set_continues(true);

        call.reply(State {
            start: Some(true),
            end: None,
            progress: None,
        })?;

        for i in 0..n {
            thread::sleep(time::Duration::from_millis(self.sleep_duration));
            call.reply(State {
                progress: Some(i * 100 / n),
                start: None,
                end: None,
            })?;
        }

        call.reply(State {
            progress: Some(100),
            start: None,
            end: None,
        })?;

        call.set_continues(false);

        call.reply(State {
            end: Some(true),
            progress: None,
            start: None,
        })
    }
}

fn run_server(address: String, timeout: u64, sleep_duration: u64) -> varlink::Result<()> {
    let myexamplemore = MyOrgExampleMore { sleep_duration };
    let myinterface = org_example_more::new(Box::new(myexamplemore));
    let service = VarlinkService::new(
        "org.varlink",
        "test service",
        "0.1",
        "http://varlink.org",
        vec![Box::new(myinterface)],
    );
    varlink::listen(service, &address, 10, timeout)?;
    Ok(())
}
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::ext::base::ExtCtxt;
use syntax::ptr::P;

use aster;

fn field_alias(field: &ast::StructField) -> Option<&ast::Lit> {
    field.node.attrs.iter()
        .find(|sa| {
            if let ast::MetaList(ref n, _) = sa.node.value.node {
                n == &"serde"
            } else {
                false
            }
        })
        .and_then(|sa| {
            if let ast::MetaList(_, ref vals) = sa.node.value.node {
                vals.iter().fold(None, |v, mi| {
                    if let ast::MetaNameValue(ref n, ref lit) = mi.node {
                        if n == &"alias" {
                            Some(lit)
                        } else {
                            v
                        }
                    } else {
                        v
                    }
                })
            } else {
                None
            }
        })
}

pub fn struct_field_strs(
    cx: &ExtCtxt,
    builder: &aster::AstBuilder,
    struct_def: &ast::StructDef,
) -> Vec<P<ast::Expr>> {
    struct_def.fields.iter()
        .map(|field| {
            match field_alias(field) {
                Some(alias) => builder.expr().build_lit(P(alias.clone())),
                None => {
                    match field.node.kind {
                        ast::NamedField(name, _) => {
                            builder.expr().str(name)
                        }
                        ast::UnnamedField(_) => {
                            cx.bug("struct has named and unnamed fields")
                        }
                    }
                }
            }
        })
        .collect()
}

pub fn default_value(field: &ast::StructField) -> bool {
    field.node.attrs.iter()
        .any(|sa| {
             if let ast::MetaItem_::MetaList(ref n, ref vals) = sa.node.value.node {
                 if n == &"serde" {
                     vals.iter()
                         .map(|mi|
                              if let ast::MetaItem_::MetaWord(ref n) = mi.node {
                                  n == &"default"
                              } else {
                                  false
                              })
                         .any(|x| x)
                 } else {
                     false
                 }
             }
             else {
                 false
             }
        })
}
<commit_msg>Mark serde field attributes as used<commit_after>use syntax::ast;
use syntax::attr;
use syntax::ext::base::ExtCtxt;
use syntax::ptr::P;

use aster;

fn field_alias(field: &ast::StructField) -> Option<&ast::Lit> {
    field.node.attrs.iter()
        .find(|sa| {
            if let ast::MetaList(ref n, _) = sa.node.value.node {
                n == &"serde"
            } else {
                false
            }
        })
        .and_then(|sa| {
            if let ast::MetaList(_, ref vals) = sa.node.value.node {
                attr::mark_used(&sa);
                vals.iter().fold(None, |v, mi| {
                    if let ast::MetaNameValue(ref n, ref lit) = mi.node {
                        if n == &"alias" {
                            Some(lit)
                        } else {
                            v
                        }
                    } else {
                        v
                    }
                })
            } else {
                None
            }
        })
}

pub fn struct_field_strs(
    cx: &ExtCtxt,
    builder: &aster::AstBuilder,
    struct_def: &ast::StructDef,
) -> Vec<P<ast::Expr>> {
    struct_def.fields.iter()
        .map(|field| {
            match field_alias(field) {
                Some(alias) => builder.expr().build_lit(P(alias.clone())),
                None => {
                    match field.node.kind {
                        ast::NamedField(name, _) => {
                            builder.expr().str(name)
                        }
                        ast::UnnamedField(_) => {
                            cx.bug("struct has named and unnamed fields")
                        }
                    }
                }
            }
        })
        .collect()
}

pub fn default_value(field: &ast::StructField) -> bool {
    field.node.attrs.iter()
        .any(|sa| {
             if let ast::MetaItem_::MetaList(ref n, ref vals) = sa.node.value.node {
                 if n == &"serde" {
                     attr::mark_used(&sa);
                     vals.iter()
                         .map(|mi|
                              if let ast::MetaItem_::MetaWord(ref n) = mi.node {
                                  n == &"default"
                              } else {
                                  false
                              })
                         .any(|x| x)
                 } else {
                     false
                 }
             }
             else {
                 false
             }
        })
}
<|endoftext|>