<commit_before> #[feature(struct_variant)];
extern mod extra;
use extra::getopts;
use std::rand;
use std::fmt;

fn randrange(min : uint, max : uint) -> uint {
    min + rand::random::<uint>() % (max - min)
}

#[deriving(Eq)]
struct ServerID(uint);

#[deriving(Eq, Ord)]
struct Term(uint);

impl fmt::Default for Term {
    fn fmt(term: &Term, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **term)
    }
}

#[deriving(Ord)]
struct Index(uint);

impl fmt::Default for Index {
    fn fmt(index: &Index, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **index)
    }
}

#[deriving(Ord, Clone)]
struct Time(uint);

impl fmt::Default for Time {
    fn fmt(time: &Time, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **time)
    }
}

struct Environment {
    clock: Time,
    network: ~[~Message],
}

impl Environment {
    fn new() -> Environment {
        Environment {
            clock: Time(0),
            network: ~[],
        }
    }
    fn make_time(&self, min: uint, max: uint) -> Time {
        Time(*self.clock + randrange(min, max))
    }
    fn make_network_latency(&self, from: ServerID, to: ServerID) -> Time {
        Time(*self.clock + randrange(2, 5))
    }
    fn multicast(&mut self, from: ServerID, to: &[ServerID], body: &MessageBody) {
        for peer in to.iter() {
            let m = ~Message {
                from: from,
                to: *peer,
                deliver: self.make_network_latency(from, *peer),
                body: *body,
            };
            self.network.push(m);
        }
    }
    fn reply(&mut self, request: &Message, response_body: &MessageBody) {
        let m = ~Message {
            from: request.to,
            to: request.from,
            deliver: self.make_network_latency(request.to, request.from),
            body: *response_body,
        };
        self.network.push(m);
    }
    fn pop_ready_messages(&mut self) -> ~[~Message] {
        let mut all = ~[];
        std::util::swap(&mut all, &mut self.network);
        let (ready, notready) = all.partition(|msg| msg.deliver <= self.clock);
        self.network = notready;
        return ready;
    }
}

struct Message {
    from: ServerID,
    to: ServerID,
    deliver: Time,
    body: MessageBody,
}

enum MessageBody {
    RequestVoteRequest {
        term: Term,
        lastLogTerm: Term,
        lastLogIndex: Index,
    },
    RequestVoteResponse {
        term: Term,
        granted: bool,
    },
    AppendEntriesRequest {
        term: Term,
        seqno: uint,
    },
    AppendEntriesResponse {
        term: Term,
        seqno: uint,
    },
}

impl fmt::Default for Message {
    fn fmt(msg: &Message, f: &mut fmt::Formatter) {
        write!(f.buf, "{} to {}: {}",
               *msg.from,
               *msg.to,
               msg.body);
    }
}

impl fmt::Default for MessageBody {
    fn fmt(b: &MessageBody, f: &mut fmt::Formatter) {
        match *b {
            RequestVoteRequest{term, lastLogTerm, lastLogIndex} =>
                write!(f.buf, "RequestVoteRequest(term: {}, lastLogTerm: {}, lastLogIndex: {})",
                       term, lastLogTerm, lastLogIndex),
            RequestVoteResponse{term, granted} =>
                write!(f.buf, "RequestVoteResponse(term: {}, granted: {})",
                       term, granted),
            AppendEntriesRequest{term, seqno} =>
                write!(f.buf, "AppendEntriesRequest(term: {}, seqno: {})",
                       term, seqno),
            AppendEntriesResponse{term, seqno} =>
                write!(f.buf, "AppendEntriesResponse(term: {}, seqno: {})",
                       term, seqno),
        }
    }
}

enum ServerState {
    Follower  { timer: Time },
    Candidate { timer: Time, votes: uint },
    Leader    { timer: Time, heartbeat_seqno: uint, acks: uint, start_time: Time},
}

impl fmt::Default for ServerState {
    fn fmt(state: &ServerState, f: &mut fmt::Formatter) {
        match *state {
            Follower{timer} => {
                write!(f.buf, "Follower(timer: {})",
                       timer)
            },
            Candidate{timer, votes} => {
                write!(f.buf, "Candidate(timer: {}, votes: {})",
                       timer, votes)
            },
            Leader{timer, heartbeat_seqno, acks, start_time} => {
                write!(f.buf, "Leader(timer: {}, seqno: {}, acks: {}, start_time: {})",
                       timer, heartbeat_seqno, acks, start_time)
            },
        }
    }
}

struct LogEntry {
    term: Term,
    // command: ~str,
}

struct Log(~[LogEntry]);

impl Log {
    fn new() -> Log {
        Log(~[])
    }
}

struct Server {
    id: ServerID,
    peers: ~[ServerID],
    term: Term,
    state: ServerState,
    vote: Option<ServerID>,
    log: Log,
}

impl Server {
    fn new(id : ServerID, peers: ~[ServerID], env: &Environment) -> Server {
        Server {
            id: id,
            peers: peers,
            term: Term(0),
            state: Follower { timer: env.make_time(150, 300) },
            log: Log::new(),
            vote: None,
        }
    }
    /*
    fn reset_timer(&mut self) {
        self.set_timer(Time(*self.env.clock + randrange(150, 300)));
    }
    fn set_timer(&mut self, time: Time) {
        match self.state {
            Follower  {timer : ref mut timer, _} |
            Candidate {timer : ref mut timer, _} =>
                { *timer = time },
            Leader => {},
        }
    }
    */
    fn tick(&mut self, env: &mut Environment) {
        let mut need_step_down = false;
        match self.state {
            Follower  {timer, _} |
            Candidate {timer, _} => {
                if timer <= env.clock {
                    self.term = Term(*self.term + 1);
                    self.vote = None;
                    self.state = Candidate {
                        timer: env.make_time(150, 300),
                        votes: 1,
                    };
                    env.multicast(self.id, self.peers, &RequestVoteRequest {
                        term: self.term,
                        lastLogTerm: Term(0),
                        lastLogIndex: Index(0),
                    });
                }
                self.try_become_leader(env);
            },
            Leader {timer: ref mut timer, heartbeat_seqno: ref mut heartbeat_seqno, acks: ref mut acks, _} => {
                if *timer <= env.clock {
                    if (*acks > (self.peers.len() + 1) / 2) {
                        *heartbeat_seqno += 1;
                        *acks = 0;
                        *timer = env.make_time(75, 76);
                        env.multicast(self.id, self.peers, &AppendEntriesRequest {
                            term: self.term,
                            seqno: *heartbeat_seqno,
                        });
                    } else {
                        need_step_down = true;
                    }
                }
            },
        }
        if need_step_down {
            println!("Failed to maintain leadership: {}", *self);
            self.step_down(env, self.term)
        }
    }
    fn step_down(&mut self, env: &Environment, term: Term) {
        self.term = term;
        self.vote = None;
        self.state = Follower {
            timer: env.make_time(150, 300),
        };
    }

    fn try_become_leader(&mut self, env: &mut Environment) {
        match self.state {
            Follower {_} => {},
            Candidate {votes, _} => {
                if votes > (self.peers.len() + 1) / 2 {
                    self.state = Leader {
                        timer: env.make_time(75, 76),
                        heartbeat_seqno: 0,
                        acks: 1,
                        start_time: env.clock,
                    };
                    env.multicast(self.id, self.peers, &AppendEntriesRequest {
                        term: self.term,
                        seqno: 0,
                    });
                }
            },
            Leader {_} => {},
        }
    }

    fn stable_leader_start_time(&self) -> Option<Time> {
        match self.state {
            Leader {heartbeat_seqno, start_time, _} if heartbeat_seqno > 4 => Some(start_time),
            _ => None,
        }
    }

    fn handle(&mut self, env: &mut Environment, msg: &Message) {
        match msg.body {
            RequestVoteRequest {term, _} => {
                let reply = |granted| {
                    env.reply(msg, &RequestVoteResponse {
                        term: self.term,
                        granted: granted,
                    });
                };
                if term < self.term {
                    reply(false);
                } else {
                    if term > self.term {
                        self.step_down(env, term);
                    }
                    match self.vote {
                        None => {
                            self.vote = Some(msg.from);
                            reply(true);
                        },
                        Some(c) => {
                            reply(c == msg.from);
                        },
                    }
                }
            },
            RequestVoteResponse {term, granted, _} => {
                if term == self.term && granted {
                    match self.state {
                        Follower {_} => {},
                        Candidate {votes: ref mut votes, _} => {
                            *votes += 1;
                        },
                        Leader {_} => {},
                    }
                    self.try_become_leader(env)
                } else if term > self.term {
                    self.step_down(env, term);
                }
            },
            AppendEntriesRequest {term, seqno} => {
                if term == self.term {
                    self.state = Follower {
                        timer: env.make_time(150, 300),
                    };
                } else if term > self.term {
                    self.step_down(env, term);
                }
                env.reply(msg, &AppendEntriesResponse {
                    term: self.term,
                    seqno: seqno,
                });
            },
            AppendEntriesResponse {term, seqno} => {
                if term == self.term {
                    match self.state {
                        Follower {_} | Candidate {_} => {},
                        Leader { heartbeat_seqno, acks: ref mut acks, _ } => {
                            if seqno == heartbeat_seqno {
                                *acks += 1;
                            }
                        },
                    }
                }
            },
        }
    }

    /*
    fn next_event_time(&self) -> Time {
        match self.state {
            Follower  {timer, _} |
            Candidate {timer, _} =>
                timer,
            Leader => Time(!0)
        }
    }
    */
}

impl fmt::Default for Server {
    fn fmt(server: &Server, f: &mut fmt::Formatter) {
        write!(f.buf, "Server {}: {}", *server.id, server.state)
    }
}

struct Cluster(~[Server]);

impl Cluster {
    fn new(env: &Environment, num_servers: uint) -> Cluster {
        let mut servers = ~[];
        for i in range(0, num_servers) {
            let mut peers = ~[];
            for j in range(0, num_servers) {
                if i != j {
                    peers.push(ServerID(j + 1));
                }
            }
            let s = Server::new(ServerID(i + 1), peers, env);
            servers.push(s);
        }
        return Cluster(servers);
    }

    fn deliver(&mut self, env: &mut Environment, msg: &Message) {
        self[*msg.to - 1].handle(env, msg);
    }
}

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("servers"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println("-h, --help   Print this help message");
        println("--servers=N  Simulate cluster with N servers");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let num_servers : uint = match matches.opt_str("servers") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of servers from '{}'", s));
            },
        }},
        None => { 5 },
    };
    let mut samples = ~[];
    for i in range(0, 10000) {
        samples.push(simulate(num_servers))
    }
    extra::sort::tim_sort(samples);
    println!("{}", samples[0]);
    println!("{}", samples[samples.len()/2]);
    println!("{}", samples[samples.len()-1]);
}

fn simulate(num_servers: uint) -> Time {
    let env = &mut Environment::new();
    let mut cluster = Cluster::new(env, num_servers);
    let mut end = None;
    while end.is_none() {
        env.clock = Time(*env.clock + 1);
        for server in cluster.mut_iter() {
            server.tick(env);
        }
        for msg in env.pop_ready_messages().move_iter() {
            cluster.deliver(env, msg);
        }
        for server in cluster.iter() {
            end = server.stable_leader_start_time();
            if end.is_some() {
                break;
            }
        }
        /*
        println!("Tick: {}", env.clock);
        for server in cluster.iter() {
            println!("{}", *server);
        }
        for message in env.network.iter() {
            println!("{}", **message);
        }
        println!("");
        */
    }
    return end.unwrap();
}

<commit_msg>Optimization/parallelism<commit_after> #[feature(struct_variant)];
extern mod extra;
use extra::getopts;
use std::rand;
use std::fmt;

fn randrange(min : uint, max : uint) -> uint {
    min + rand::random::<uint>() % (max - min)
}

#[deriving(Eq)]
struct ServerID(uint);

#[deriving(Eq, Ord)]
struct Term(uint);

impl fmt::Default for Term {
    fn fmt(term: &Term, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **term)
    }
}

#[deriving(Ord)]
struct Index(uint);

impl fmt::Default for Index {
    fn fmt(index: &Index, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **index)
    }
}

#[deriving(Ord, Clone)]
struct Time(uint);

impl fmt::Default for Time {
    fn fmt(time: &Time, f: &mut fmt::Formatter) {
        write!(f.buf, "{}", **time)
    }
}

struct Environment {
    clock: Time,
    network: ~[~Message],
}

impl Environment {
    fn new() -> Environment {
        Environment {
            clock: Time(0),
            network: ~[],
        }
    }
    fn make_time(&self, min: uint, max: uint) -> Time {
        Time(*self.clock + randrange(min, max))
    }
    fn make_network_latency(&self, from: ServerID, to: ServerID) -> Time {
        Time(*self.clock + randrange(2, 5))
    }
    fn multicast(&mut self, from: ServerID, to: &[ServerID], body: &MessageBody) {
        for peer in to.iter() {
            let m = ~Message {
                from: from,
                to: *peer,
                deliver: self.make_network_latency(from, *peer),
                body: *body,
            };
            self.network.push(m);
        }
    }
    fn reply(&mut self, request: &Message, response_body: &MessageBody) {
        let m = ~Message {
            from: request.to,
            to: request.from,
            deliver: self.make_network_latency(request.to, request.from),
            body: *response_body,
        };
        self.network.push(m);
    }
    fn pop_ready_messages(&mut self) -> ~[~Message] {
        if !self.network.iter().any(|msg| msg.deliver <= self.clock) {
            return ~[];
        }
        let mut all = ~[];
        std::util::swap(&mut all, &mut self.network);
        let (ready, notready) = all.partition(|msg| msg.deliver <= self.clock);
        self.network = notready;
        return ready;
    }
}

struct Message {
    from: ServerID,
    to: ServerID,
    deliver: Time,
    body: MessageBody,
}

enum MessageBody {
    RequestVoteRequest {
        term: Term,
        lastLogTerm: Term,
        lastLogIndex: Index,
    },
    RequestVoteResponse {
        term: Term,
        granted: bool,
    },
    AppendEntriesRequest {
        term: Term,
        seqno: uint,
    },
    AppendEntriesResponse {
        term: Term,
        seqno: uint,
    },
}

impl fmt::Default for Message {
    fn fmt(msg: &Message, f: &mut fmt::Formatter) {
        write!(f.buf, "{} to {}: {}",
               *msg.from,
               *msg.to,
               msg.body);
    }
}

impl fmt::Default for MessageBody {
    fn fmt(b: &MessageBody, f: &mut fmt::Formatter) {
        match *b {
            RequestVoteRequest{term, lastLogTerm, lastLogIndex} =>
                write!(f.buf, "RequestVoteRequest(term: {}, lastLogTerm: {}, lastLogIndex: {})",
                       term, lastLogTerm, lastLogIndex),
            RequestVoteResponse{term, granted} =>
                write!(f.buf, "RequestVoteResponse(term: {}, granted: {})",
                       term, granted),
            AppendEntriesRequest{term, seqno} =>
                write!(f.buf, "AppendEntriesRequest(term: {}, seqno: {})",
                       term, seqno),
            AppendEntriesResponse{term, seqno} =>
                write!(f.buf, "AppendEntriesResponse(term: {}, seqno: {})",
                       term, seqno),
        }
    }
}

enum ServerState {
    Follower  { timer: Time },
    Candidate { timer: Time, votes: uint },
    Leader    { timer: Time, heartbeat_seqno: uint, acks: uint, start_time: Time},
}

impl fmt::Default for ServerState {
    fn fmt(state: &ServerState, f: &mut fmt::Formatter) {
        match *state {
            Follower{timer} => {
                write!(f.buf, "Follower(timer: {})",
                       timer)
            },
            Candidate{timer, votes} => {
                write!(f.buf, "Candidate(timer: {}, votes: {})",
                       timer, votes)
            },
            Leader{timer, heartbeat_seqno, acks, start_time} => {
                write!(f.buf, "Leader(timer: {}, seqno: {}, acks: {}, start_time: {})",
                       timer, heartbeat_seqno, acks, start_time)
            },
        }
    }
}

struct LogEntry {
    term: Term,
    // command: ~str,
}

struct Log(~[LogEntry]);

impl Log {
    fn new() -> Log {
        Log(~[])
    }
}

struct Server {
    id: ServerID,
    peers: ~[ServerID],
    term: Term,
    state: ServerState,
    vote: Option<ServerID>,
    log: Log,
}

impl Server {
    fn new(id : ServerID, peers: ~[ServerID], env: &Environment) -> Server {
        Server {
            id: id,
            peers: peers,
            term: Term(0),
            state: Follower { timer: env.make_time(150, 300) },
            log: Log::new(),
            vote: None,
        }
    }
    /*
    fn reset_timer(&mut self) {
        self.set_timer(Time(*self.env.clock + randrange(150, 300)));
    }
    fn set_timer(&mut self, time: Time) {
        match self.state {
            Follower  {timer : ref mut timer, _} |
            Candidate {timer : ref mut timer, _} =>
                { *timer = time },
            Leader => {},
        }
    }
    */
    fn tick(&mut self, env: &mut Environment) {
        let mut need_step_down = false;
        match self.state {
            Follower  {timer, _} |
            Candidate {timer, _} => {
                if timer <= env.clock {
                    self.term = Term(*self.term + 1);
                    self.vote = None;
                    self.state = Candidate {
                        timer: env.make_time(150, 300),
                        votes: 1,
                    };
                    env.multicast(self.id, self.peers, &RequestVoteRequest {
                        term: self.term,
                        lastLogTerm: Term(0),
                        lastLogIndex: Index(0),
                    });
                }
                self.try_become_leader(env);
            },
            Leader {timer: ref mut timer, heartbeat_seqno: ref mut heartbeat_seqno, acks: ref mut acks, _} => {
                if *timer <= env.clock {
                    if (*acks > (self.peers.len() + 1) / 2) {
                        *heartbeat_seqno += 1;
                        *acks = 0;
                        *timer = env.make_time(75, 76);
                        env.multicast(self.id, self.peers, &AppendEntriesRequest {
                            term: self.term,
                            seqno: *heartbeat_seqno,
                        });
                    } else {
                        need_step_down = true;
                    }
                }
            },
        }
        if need_step_down {
            println!("Failed to maintain leadership: {}", *self);
            self.step_down(env, self.term)
        }
    }
    fn step_down(&mut self, env: &Environment, term: Term) {
        self.term = term;
        self.vote = None;
        self.state = Follower {
            timer: env.make_time(150, 300),
        };
    }

    fn try_become_leader(&mut self, env: &mut Environment) {
        match self.state {
            Follower {_} => {},
            Candidate {votes, _} => {
                if votes > (self.peers.len() + 1) / 2 {
                    self.state = Leader {
                        timer: env.make_time(75, 76),
                        heartbeat_seqno: 0,
                        acks: 1,
                        start_time: env.clock,
                    };
                    env.multicast(self.id, self.peers, &AppendEntriesRequest {
                        term: self.term,
                        seqno: 0,
                    });
                }
            },
            Leader {_} => {},
        }
    }

    fn stable_leader_start_time(&self) -> Option<Time> {
        match self.state {
            Leader {heartbeat_seqno, start_time, _} if heartbeat_seqno > 4 => Some(start_time),
            _ => None,
        }
    }

    fn handle(&mut self, env: &mut Environment, msg: &Message) {
        match msg.body {
            RequestVoteRequest {term, _} => {
                let reply = |granted| {
                    env.reply(msg, &RequestVoteResponse {
                        term: self.term,
                        granted: granted,
                    });
                };
                if term < self.term {
                    reply(false);
                } else {
                    if term > self.term {
                        self.step_down(env, term);
                    }
                    match self.vote {
                        None => {
                            self.vote = Some(msg.from);
                            reply(true);
                        },
                        Some(c) => {
                            reply(c == msg.from);
                        },
                    }
                }
            },
            RequestVoteResponse {term, granted, _} => {
                if term == self.term && granted {
                    match self.state {
                        Follower {_} => {},
                        Candidate {votes: ref mut votes, _} => {
                            *votes += 1;
                        },
                        Leader {_} => {},
                    }
                    self.try_become_leader(env)
                } else if term > self.term {
                    self.step_down(env, term);
                }
            },
            AppendEntriesRequest {term, seqno} => {
                if term == self.term {
                    self.state = Follower {
                        timer: env.make_time(150, 300),
                    };
                } else if term > self.term {
                    self.step_down(env, term);
                }
                env.reply(msg, &AppendEntriesResponse {
                    term: self.term,
                    seqno: seqno,
                });
            },
            AppendEntriesResponse {term, seqno} => {
                if term == self.term {
                    match self.state {
                        Follower {_} | Candidate {_} => {},
                        Leader { heartbeat_seqno, acks: ref mut acks, _ } => {
                            if seqno == heartbeat_seqno {
                                *acks += 1;
                            }
                        },
                    }
                }
            },
        }
    }

    /*
    fn next_event_time(&self) -> Time {
        match self.state {
            Follower  {timer, _} |
            Candidate {timer, _} =>
                timer,
            Leader => Time(!0)
        }
    }
    */
}

impl fmt::Default for Server {
    fn fmt(server: &Server, f: &mut fmt::Formatter) {
        write!(f.buf, "Server {}: {}", *server.id, server.state)
    }
}

struct Cluster(~[Server]);

impl Cluster {
    fn new(env: &Environment, num_servers: uint) -> Cluster {
        let mut servers = ~[];
        for i in range(0, num_servers) {
            let mut peers = ~[];
            for j in range(0, num_servers) {
                if i != j {
                    peers.push(ServerID(j + 1));
                }
            }
            let s = Server::new(ServerID(i + 1), peers, env);
            servers.push(s);
        }
        return Cluster(servers);
    }

    fn deliver(&mut self, env: &mut Environment, msg: &Message) {
        self[*msg.to - 1].handle(env, msg);
    }
}

fn main() {
    let args = std::os::args();
    let opts = [
        getopts::optflag("h"),
        getopts::optflag("help"),
        getopts::optopt("samples"),
        getopts::optopt("servers"),
        getopts::optopt("tasks"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => { fail!(f.to_err_msg()) },
    };
    let usage = || {
        println!("Usage: {} [options]", args[0]);
        println("-h, --help    Print this help message");
        println("--samples=N   Number of simulations (default 100,000)");
        println("--servers=N   Simulate cluster with N servers");
        println("--tasks=N     Number of parallel jobs (default 1)");
    };
    if matches.opt_present("h") || matches.opt_present("help") {
        usage();
        return;
    }
    if !matches.free.is_empty() {
        usage();
        fail!(format!("Extra arguments: {}", matches.free.len()));
    }
    let num_samples : uint = match matches.opt_str("samples") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of samples from '{}'", s));
            },
        }},
        None => { 100000 },
    };
    let num_servers : uint = match matches.opt_str("servers") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of servers from '{}'", s));
            },
        }},
        None => { 5 },
    };
    let num_tasks : uint = match matches.opt_str("tasks") {
        Some(s) => { match std::from_str::from_str(s) {
            Some(i) => { i },
            None => {
                usage();
                fail!(format!("Couldn't parse number of tasks from '{}'", s));
            },
        }},
        None => { 1 },
    };

    let (port, chan): (Port<~[Time]>, Chan<~[Time]>) = stream();
    let chan = std::comm::SharedChan::new(chan);
    for tid in range(0, num_tasks) {
        let child_chan = chan.clone();
        do spawn || {
            let mut samples = ~[];
            let n = if tid == 0 {
                // get the odd one left over
                num_samples - (num_samples / num_tasks) * (num_tasks - 1)
            } else {
                num_samples / num_tasks
            };
            samples.reserve(n);
            do n.times {
                samples.push(simulate(num_servers))
            }
            extra::sort::tim_sort(samples);
            child_chan.send(samples);
        }
    }

    let mut samples = ~[];
    samples.reserve(num_samples);
    do num_tasks.times {
        samples.push_all(port.recv());
    }
    extra::sort::tim_sort(samples);

    println!("Across {} trials:", samples.len());
    println!("Min:    {} ticks", samples[0]);
    println!("Median: {} ticks", samples[samples.len()/2]);
    println!("Max:    {} ticks", samples[samples.len()-1]);
}

fn simulate(num_servers: uint) -> Time {
    let env = &mut Environment::new();
    let mut cluster = Cluster::new(env, num_servers);
    let mut end = None;
    while end.is_none() {
        env.clock = Time(*env.clock + 1);
        for server in cluster.mut_iter() {
            server.tick(env);
        }
        for msg in env.pop_ready_messages().move_iter() {
            cluster.deliver(env, msg);
        }
        for server in cluster.iter() {
            end = server.stable_leader_start_time();
            if end.is_some() {
                break;
            }
        }
        /*
        println!("Tick: {}", env.clock);
        for server in cluster.iter() {
            println!("{}", *server);
        }
        for message in env.network.iter() {
            println!("{}", **message);
        }
        println!("");
        */
    }
    return end.unwrap();
}

<|endoftext|>


<commit_before>//! A collection of simple utilities for building
//! flake-free testable systems.
// #![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate serde;
extern crate libc;
extern crate rand;

use std::time::{Duration, SystemTime, UNIX_EPOCH};
use std::sync::{Arc, Mutex};
use std::cell::RefCell;
use std::fmt::Debug;

use serde::de::DeserializeOwned;
use serde::Serialize;

/// Spawn threads with linux realtime priorities, and
/// inherit the spawner's shared seeded random number
/// generator and clock.
pub mod spawn;

/// Files that can simulate power failures by losing
/// data written after the last sync.
pub mod file;

/// A trait for building networked systems
/// that can be plugged into simulated networks
/// and partition tested in accelerated time.
pub trait Reactor: Debug + Clone {
    type Peer: std::net::ToSocketAddrs;
    type Message: Serialize + DeserializeOwned;
    type Config;
    type Error;

    const PERIODIC_INTERVAL: Option<Duration> = None;

    fn start(config: Self::Config) -> Result<Self, Self::Error>;

    fn receive(
        &mut self,
        from: Self::Peer,
        msg: Self::Message,
    ) -> Vec<(Self::Peer, Self::Message)>;

    fn periodic(&mut self) -> Vec<(Self::Peer, Self::Message)>;
}

thread_local! {
    pub static CONTEXT: RefCell<Arc<Context>> = RefCell::new(Arc::new(Context::default()));
}

fn context<'a>() -> Arc<Context> {
    CONTEXT.with(|c| c.borrow().clone())
}

fn set_context(context: Arc<Context>) {
    CONTEXT.with(|c| *c.borrow_mut() = context);
}

mod context;

use context::Context;

pub use context::{Rand, now, seed, set_seed, set_time, sleep, thread_rng};
<commit_msg>add default periodic that panics, because it only gets called if the PERIODIC_INTERVAL is changed from None<commit_after>//! A collection of simple utilities for building
//! flake-free testable systems.
// #![deny(missing_docs)]
#![cfg_attr(test, deny(warnings))]

extern crate serde;
extern crate libc;
extern crate rand;

use std::time::{Duration, SystemTime, UNIX_EPOCH};
use std::sync::{Arc, Mutex};
use std::cell::RefCell;
use std::fmt::Debug;

use serde::de::DeserializeOwned;
use serde::Serialize;

/// Spawn threads with linux realtime priorities, and
/// inherit the spawner's shared seeded random number
/// generator and clock.
pub mod spawn;

/// Files that can simulate power failures by losing
/// data written after the last sync.
pub mod file;

/// A trait for building networked systems
/// that can be plugged into simulated networks
/// and partition tested in accelerated time.
pub trait Reactor: Debug + Clone {
    type Peer: std::net::ToSocketAddrs;
    type Message: Serialize + DeserializeOwned;
    type Config;
    type Error;

    const PERIODIC_INTERVAL: Option<Duration> = None;

    fn start(config: Self::Config) -> Result<Self, Self::Error>;

    fn receive(
        &mut self,
        from: Self::Peer,
        msg: Self::Message,
    ) -> Vec<(Self::Peer, Self::Message)>;

    fn periodic(&mut self) -> Vec<(Self::Peer, Self::Message)> {
        unimplemented!()
    }
}

thread_local! {
    pub static CONTEXT: RefCell<Arc<Context>> = RefCell::new(Arc::new(Context::default()));
}

fn context<'a>() -> Arc<Context> {
    CONTEXT.with(|c| c.borrow().clone())
}

fn set_context(context: Arc<Context>) {
    CONTEXT.with(|c| *c.borrow_mut() = context);
}

mod context;

use context::Context;

pub use context::{Rand, now, seed, set_seed, set_time, sleep, thread_rng};
<|endoftext|>


<commit_before>#[macro_use]
extern crate simulator;
extern crate deterministic;
extern crate bincode;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::collections::HashMap;
use std::time::SystemTime;

use deterministic::{Reactor, now, set_time};

type ReqId = usize;

struct IdGen {
    peers: Vec<String>,
    in_flight: HashMap<ReqId, Pending>,
    req_counter: usize,
}

struct IdGenConf {
    peers: Vec<String>,
}

struct Pending {
    accepted: usize,
    rejected: usize,
    from: String,
    their_req_id: usize,
    arrived: SystemTime,
}

#[derive(Debug, Serialize, Deserialize)]
enum Msg {
    ClientReq { req_id: usize },
    ClientRes { req_id: usize, new_id: usize },
    ProposeId { req_id: usize },
    AcceptId { req_id: usize },
    RejectId { req_id: usize, highest: usize },
}

use Msg::*;

impl IdGen {
    fn propose(
        &mut self,
        from: String,
        their_req_id: usize,
    ) -> Vec<(String, Msg)> {
        self.req_counter += 1;
        let req_id = self.req_counter;
        self.in_flight.insert(
            req_id,
            Pending {
                accepted: 0,
                rejected: 0,
                from: from,
                their_req_id: their_req_id,
                arrived: now(),
            },
        );
        self.peers
            .iter()
            .map(|p| {
                (
                    p.clone(),
                    ProposeId {
                        req_id,
                    },
                )
            })
            .collect()

    }
}

impl Reactor for IdGen {
    type Config = IdGenConf;
    type Error = ();
    type Peer = String;
    type Message = Msg;

    fn start(conf: IdGenConf) -> Result<IdGen, ()> {
        Ok(IdGen {
            peers: conf.peers,
            in_flight: HashMap::new(),
            req_counter: 0,
        })
    }

    fn receive(
        &mut self,
        from: Self::Peer,
        msg: Self::Message,
    ) -> Vec<(Self::Peer, Self::Message)> {
        match msg {
            ClientReq {
                req_id,
            } => self.propose(from, req_id),
            ClientRes {
                ..
            } => panic!("somehow received a ClientRes: {:?}", msg),
            ProposeId {
                req_id,
            } => {
                if req_id > self.req_counter {
                    self.req_counter = req_id;
                    vec![
                        (
                            from,
                            AcceptId {
                                req_id,
                            }
                        ),
                    ]
                } else {
                    vec![
                        (
                            from,
                            RejectId {
                                req_id: req_id,
                                highest: self.req_counter,
                            }
                        ),
                    ]
                }
            }
            AcceptId {
                req_id,
            } => {
                let mut pending = self.in_flight.remove(&req_id);
                if let Some(mut pending) = pending {
                    pending.accepted += 1;
                    if pending.accepted > self.peers.len() / 2 {
                        vec![
                            (
                                pending.from,
                                ClientRes {
                                    req_id: pending.their_req_id,
                                    new_id: req_id,
                                }
                            ),
                        ]
                    } else {
                        self.in_flight.insert(req_id, pending);
                        vec![]
                    }
                } else {
                    vec![]
                }
            }
            RejectId {
                req_id,
                highest,
            } => {
                if highest > self.req_counter {
                    self.req_counter = highest;
                }
                let mut pending = self.in_flight.remove(&req_id);
                if let Some(mut pending) = pending {
                    pending.rejected += 1;
                    if pending.rejected > self.peers.len() / 2 {
                        // retry
                        self.propose(pending.from, pending.their_req_id)
                    } else {
                        self.in_flight.insert(req_id, pending);
                        vec![]
                    }
                } else {
                    vec![]
                }
            }
        }
    }
}

#[test]
fn idgen_is_linearizable() {
    use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering::SeqCst};

    static REQ_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;

    /*
    simulate! {
        IdGen 1..3,
        Get() -> usize {

        }
    }
    */
}
<commit_msg>clear compiler warnings<commit_after>extern crate simulator;
extern crate deterministic;
extern crate bincode;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::collections::HashMap;

use deterministic::Reactor;

type ReqId = usize;

struct IdGen {
    peers: Vec<String>,
    in_flight: HashMap<ReqId, Pending>,
    req_counter: usize,
}

struct IdGenConf {
    peers: Vec<String>,
}

struct Pending {
    accepted: usize,
    rejected: usize,
    from: String,
    their_req_id: usize,
}

#[derive(Debug, Serialize, Deserialize)]
enum Msg {
    ClientReq { req_id: usize },
    ClientRes { req_id: usize, new_id: usize },
    ProposeId { req_id: usize },
    AcceptId { req_id: usize },
    RejectId { req_id: usize, highest: usize },
}

use Msg::*;

impl IdGen {
    fn propose(
        &mut self,
        from: String,
        their_req_id: usize,
    ) -> Vec<(String, Msg)> {
        self.req_counter += 1;
        let req_id = self.req_counter;
        self.in_flight.insert(
            req_id,
            Pending {
                accepted: 0,
                rejected: 0,
                from: from,
                their_req_id: their_req_id,
            },
        );
        self.peers
            .iter()
            .map(|p| {
                (
                    p.clone(),
                    ProposeId {
                        req_id,
                    },
                )
            })
            .collect()

    }
}

impl Reactor for IdGen {
    type Config = IdGenConf;
    type Error = ();
    type Peer = String;
    type Message = Msg;

    fn start(conf: IdGenConf) -> Result<IdGen, ()> {
        Ok(IdGen {
            peers: conf.peers,
            in_flight: HashMap::new(),
            req_counter: 0,
        })
    }

    fn receive(
        &mut self,
        from: Self::Peer,
        msg: Self::Message,
    ) -> Vec<(Self::Peer, Self::Message)> {
        match msg {
            ClientReq {
                req_id,
            } => self.propose(from, req_id),
            ClientRes {
                ..
            } => panic!("somehow received a ClientRes: {:?}", msg),
            ProposeId {
                req_id,
            } => {
                if req_id > self.req_counter {
                    self.req_counter = req_id;
                    vec![
                        (
                            from,
                            AcceptId {
                                req_id,
                            }
                        ),
                    ]
                } else {
                    vec![
                        (
                            from,
                            RejectId {
                                req_id: req_id,
                                highest: self.req_counter,
                            }
                        ),
                    ]
                }
            }
            AcceptId {
                req_id,
            } => {
                let mut pending = self.in_flight.remove(&req_id);
                if let Some(mut pending) = pending {
                    pending.accepted += 1;
                    if pending.accepted > self.peers.len() / 2 {
                        vec![
                            (
                                pending.from,
                                ClientRes {
                                    req_id: pending.their_req_id,
                                    new_id: req_id,
                                }
                            ),
                        ]
                    } else {
                        self.in_flight.insert(req_id, pending);
                        vec![]
                    }
                } else {
                    vec![]
                }
            }
            RejectId {
                req_id,
                highest,
            } => {
                if highest > self.req_counter {
                    self.req_counter = highest;
                }
                let mut pending = self.in_flight.remove(&req_id);
                if let Some(mut pending) = pending {
                    pending.rejected += 1;
                    if pending.rejected > self.peers.len() / 2 {
                        // retry
                        self.propose(pending.from, pending.their_req_id)
                    } else {
                        self.in_flight.insert(req_id, pending);
                        vec![]
                    }
                } else {
                    vec![]
                }
            }
        }
    }
}

#[test]
fn idgen_is_linearizable() {
    /*
    simulate! {
        IdGen 1..3,
        Get() -> usize {

        }
    }
    */
}
<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    sync::Arc,
};

use super::behaviors::{MouseBehavior, SelectionBehavior};

use crate::{api::prelude::*, prelude::*, proc_macros::*, theme::prelude::*};

// --- KEYS --

static CONTAINER: &str = "container";
static ITEMS_PANEL: &str = "items_panel";

// --- KEYS --

type SelectedItem = Option<Entity>;

#[derive(Debug, Copy, Clone)]
enum Action {
    CheckMouseUpOutside { position: Point },
}

/// The `ComboBoxItemState` handles the interaction an selection of a `ComboBoxItem`.
#[derive(Default, AsAny)]
pub struct ComboBoxItemState {
    request_selection_toggle: Cell<bool>,
    index: usize,
    selected_container: Entity,
    combo_box: Entity,
    // ugly work around for item builder context clone, todo make it better 😉
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
}

impl ComboBoxItemState {
    fn toggle_selection(&self) {
        self.request_selection_toggle.set(true);
    }
}

impl State for ComboBoxItemState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        let selected_index = ctx
            .get_widget(self.combo_box)
            .clone_or_default::<i32>("selected_index");
        let selected: bool = *ctx.widget().get("selected");

        if selected_index >= 0 && (selected_index as usize) == self.index && !selected {
            self.request_selection_toggle.set(true);
        }

        if !ctx.widget().get::<bool>("enabled") || !self.request_selection_toggle.get() {
            return;
        }
        self.request_selection_toggle.set(false);

        let entity = ctx.entity;

        // unselect previous selected item.
        if let Some(item) = ctx
            .get_widget(self.combo_box)
            .clone::<SelectedItem>("selected_item")
        {
            ctx.get_widget(item).set("selected", false);
            ctx.get_widget(item)
                .get_mut::<Selector>("selector")
                .clear_state();
            ctx.get_widget(item).update(false);
        }

        ctx.widget().set("selected", true);
        ctx.widget()
            .get_mut::<Selector>("selector")
            .set_state("selected");
        ctx.widget().update(false);
        ctx.get_widget(self.combo_box)
            .set("selected_index", self.index as i32);
        ctx.get_widget(self.combo_box)
            .set("selected_item", Some(entity));

        // Add selected content to combobox
        let index = self.index;
        let selected_container = self.selected_container;
        if let Some(builder) = &self.builder {
            ctx.clear_children_of(selected_container);
            let build_context = &mut ctx.build_context();
            let selected_content = builder.borrow()(build_context, index);
            build_context.append_child(selected_container, selected_content);
        }
    }
}

widget!(
    /// The `ComboBoxItem` describes an item inside of a `ComboBox`.
    ///
    /// **style:** `combo_box_item``
    ComboBoxItem<ComboBoxItemState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool
    }
);

impl ComboBoxItem {
    fn selected_container(mut self, selected_container: impl Into<Entity>) -> Self {
        self.state_mut().selected_container = selected_container.into();
        self
    }

    fn index(mut self, index: usize) -> Self {
        self.state_mut().index = index;
        self
    }

    fn combo_box(mut self, combo_box: impl Into<Entity>) -> Self {
        self.state_mut().combo_box = combo_box.into();
        self
    }

    // Define the template build function for the selected content of the ComboBoxItems.
    fn items_builder(
        &mut self,
        builder: &Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>,
    ) {
        self.state_mut().builder = Some(builder.clone());
    }
}

impl Template for ComboBoxItem {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("ComboBoxItem")
            .style("combo_box_item")
            .min_width(64)
            .height(24)
            .selected(false)
            .pressed(false)
            .padding(0)
            .background("transparent")
            .border_radius(0)
            .border_width(0)
            .border_brush("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(32)
            .font("Roboto-Regular")
            .child(
                MouseBehavior::new()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .build(ctx),
            )
            .on_click(move |states, _| {
                states.get::<ComboBoxItemState>(id).toggle_selection();
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }

    fn layout(&self) -> Box<dyn Layout> {
        Box::new(PaddingLayout::new())
    }
}

/// The `ComboBoxState` is used to manipulate the position of the thumb of the slider widget.
#[derive(Default, AsAny)]
pub struct ComboBoxState {
    popup: Entity,
    action: Option<Action>,
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
    count: usize,
    items_panel: Entity,
    selected_container: Entity,
}

impl ComboBoxState {
    fn action(&mut self, action: impl Into<Option<Action>>) {
        self.action = action.into();
    }

    // closes the popup on mouse up outside of the combobox and popup.
    fn close_popup(&mut self, ctx: &mut Context, p: Point) {
        let combo_box_position = ctx.widget().clone::<Point>("position");
        let combo_box_bounds = ctx.widget().clone::<Rectangle>("bounds");

        let combo_box_global_bounds = Rectangle::new(combo_box_position, combo_box_bounds.size());

        if !combo_box_global_bounds.contains(p) {
            ctx.widget().set("selected", false);
            ctx.widget().get_mut::<Selector>("selector").clear_state();
            ctx.get_widget(self.popup)
                .set("visibility", Visibility::Collapsed);
            ctx.get_widget(self.popup).update(false);
            ctx.widget().update(false);
        }
    }
}

impl State for ComboBoxState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        let count = ctx.widget().clone_or_default::<usize>("count");
        let entity = ctx.entity;

        // build the combobox items
        if count != self.count {
            if let Some(builder) = &self.builder {
                ctx.clear_children_of(self.items_panel);

                for i in 0..count {
                    let item = {
                        let build_context = &mut ctx.build_context();
                        let child = builder.borrow()(build_context, i);
                        let mut item = ComboBoxItem::new()
                            .index(i)
                            .combo_box(entity)
                            .selected_container(self.selected_container);

                        if let Some(builder) = &self.builder {
                            item.items_builder(builder);
                        }
                        let item = item.build(build_context);

                        let mouse_behavior =
                            MouseBehavior::new().target(item.0).build(build_context);
                        build_context.register_shared_property::<Selector>(
                            "selector",
                            mouse_behavior,
                            item,
                        );
                        build_context.register_shared_property::<bool>(
                            "pressed",
                            mouse_behavior,
                            item,
                        );
                        build_context.append_child(item, mouse_behavior);

                        build_context.register_shared_property::<Brush>("foreground", child, item);
                        build_context.register_shared_property::<f32>("opacity", item, entity);
                        build_context.register_shared_property::<f32>("opacity", child, entity);
                        build_context.register_shared_property::<f64>("font_size", child, item);
                        build_context.append_child(self.items_panel, item);
                        build_context.append_child(mouse_behavior, child);

                        item
                    };
                    ctx.get_widget(item).update_widget(entity, false, false);
                }
            }

            self.count = count;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        if self.action.is_none() || !(*ctx.widget().get::<bool>("selected")) {
            return;
        }

        if let Some(action) = self.action {
            match action {
                Action::CheckMouseUpOutside { position } => {
                    self.close_popup(ctx, position);
                }
            }
        }
    }

    fn cleanup(&mut self, _: &mut Registry, ctx: &mut Context) {
        let _ = ctx.remove_child_from_overlay(self.popup);
    }
}

// todo use code of list view item, by create combobox item insert entity of popup container

widget!(
    /// The `ComboBox` represents an selection widget with a drop-down list.
    ///
    /// **style:** `combo_box`
    ComboBox<ComboBoxState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shared the count.
        count: usize,

        /// Sets or shares the selected index. If the value is -1 no item is selected.
        selected_index: i32,

        /// The entity of the selected item.
        selected_item: SelectedItem,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the flag if the drop down is open.
        selected: bool,

        /// Sets or shares the icon property.
        icon: String,

        /// Sets or shares the icon brush property.
        icon_brush: Brush,

        /// Sets or share the icon font size property.
        icon_size: f64,

        /// Sets or shares the icon font property.
        icon_font: String
    }
);

impl ComboBox {
    /// Define the template build function for the content of the ComboBoxItems.
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static + Clone>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Arc::new(RefCell::new(builder)));
        self
    }
}

impl Template for ComboBox {
    fn template(mut self, id: Entity, ctx: &mut BuildContext) -> Self {
        let selected_container = Container::new().attach(Grid::column(0)).build(ctx);

        let container = Container::new()
            .id(CONTAINER)
            .background(id)
            .border_radius(id)
            .border_width(id)
            .border_brush(id)
            .padding(id)
            .child(
                Grid::new()
                    .columns(Columns::create().push("*").push(4.0).push(14.0))
                    .child(selected_container)
                    .child(
                        FontIconBlock::new()
                            .attach(Grid::column(2))
                            .v_align("center")
                            .icon_brush(id)
                            .icon_size(id)
                            .icon_font(id)
                            .icon(id)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .build(ctx);
        self.state_mut().selected_container = selected_container;

        let items_panel = Stack::new()
            .v_align("start")
            .id(ITEMS_PANEL)
            .orientation("vertical")
            .build(ctx);

        self.state_mut().items_panel = items_panel;
        let scroll_viewer = ScrollViewer::new()
            .mode(("disabled", "auto"))
            .child(items_panel)
            .build(ctx);

        let popup = Popup::new()
            .height(200.0)
            .open(("selected", id))
            .child(scroll_viewer)
            .child(
                ScrollIndicator::new()
                    .padding(2.0)
                    .content_bounds(("bounds", items_panel))
                    .view_port_bounds(("bounds", scroll_viewer))
                    .scroll_padding(("padding", scroll_viewer))
                    .mode(scroll_viewer)
                    .opacity(id)
                    .build(ctx),
            )
            .target(container.0)
            .build(ctx);
        self.state_mut().popup = popup;

        let _ = ctx.append_child_to_overlay(popup);

        self.name("ComboBox")
            .style("combo_box")
            .icon(material_icons_font::MD_ARROW_DROP_DOWN)
            .icon_font("MaterialIcons-Regular")
            .icon_size(fonts::ICON_FONT_SIZE_12)
            .icon_brush(colors::LINK_WATER_COLOR)
            .height(32.0)
            .min_width(80.0)
            .selected(false)
            .selected_index(-1)
            .child(
                MouseBehavior::new()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .child(
                        SelectionBehavior::new()
                            .selected(id)
                            .enabled(id)
                            .target(id.0)
                            .child(container)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_global_mouse_up(move |states, e| {
                states
                    .get_mut::<ComboBoxState>(id)
                    .action(Action::CheckMouseUpOutside {
                        position: e.position,
                    })
            })
    }
}
<commit_msg>add selected item change filter on combobox<commit_after>use std::{
    cell::{Cell, RefCell},
    sync::Arc,
};

use super::behaviors::{MouseBehavior, SelectionBehavior};

use crate::{api::prelude::*, prelude::*, proc_macros::*, theme::prelude::*};

// --- KEYS --

static CONTAINER: &str = "container";
static ITEMS_PANEL: &str = "items_panel";

// --- KEYS --

type SelectedItem = Option<Entity>;

#[derive(Debug, Copy, Clone)]
enum Action {
    CheckMouseUpOutside { position: Point },
}

/// The `ComboBoxItemState` handles the interaction an selection of a `ComboBoxItem`.
#[derive(Default, AsAny)]
pub struct ComboBoxItemState {
    request_selection_toggle: Cell<bool>,
    index: usize,
    selected_container: Entity,
    combo_box: Entity,
    // ugly work around for item builder context clone, todo make it better 😉
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
}

impl ComboBoxItemState {
    fn toggle_selection(&self) {
        self.request_selection_toggle.set(true);
    }
}

impl State for ComboBoxItemState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        let selected_index = ctx
            .get_widget(self.combo_box)
            .clone_or_default::<i32>("selected_index");
        let selected: bool = *ctx.widget().get("selected");

        if selected_index >= 0 && (selected_index as usize) == self.index && !selected {
            self.request_selection_toggle.set(true);
        }

        if !ctx.widget().get::<bool>("enabled") || !self.request_selection_toggle.get() {
            return;
        }
        self.request_selection_toggle.set(false);

        let entity = ctx.entity;

        // unselect previous selected item.
        if let Some(item) = ctx
            .get_widget(self.combo_box)
            .clone::<SelectedItem>("selected_item")
        {
            ctx.get_widget(item).set("selected", false);
            ctx.get_widget(item)
                .get_mut::<Selector>("selector")
                .clear_state();
            ctx.get_widget(item).update(false);
        }

        ctx.widget().set("selected", true);
        ctx.widget()
            .get_mut::<Selector>("selector")
            .set_state("selected");
        ctx.widget().update(false);
        ctx.get_widget(self.combo_box)
            .set("selected_index", self.index as i32);
        ctx.get_widget(self.combo_box)
            .set("selected_item", Some(entity));

        // Add selected content to combobox
        let index = self.index;
        let selected_container = self.selected_container;
        if let Some(builder) = &self.builder {
            ctx.clear_children_of(selected_container);
            let build_context = &mut ctx.build_context();
            let selected_content = builder.borrow()(build_context, index);
            build_context.append_child(selected_container, selected_content);
        }
    }
}

widget!(
    /// The `ComboBoxItem` describes an item inside of a `ComboBox`.
    ///
    /// **style:** `combo_box_item``
    ComboBoxItem<ComboBoxItemState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the selected property.
        selected: bool
    }
);

impl ComboBoxItem {
    fn selected_container(mut self, selected_container: impl Into<Entity>) -> Self {
        self.state_mut().selected_container = selected_container.into();
        self
    }

    fn index(mut self, index: usize) -> Self {
        self.state_mut().index = index;
        self
    }

    fn combo_box(mut self, combo_box: impl Into<Entity>) -> Self {
        self.state_mut().combo_box = combo_box.into();
        self
    }

    // Define the template build function for the selected content of the ComboBoxItems.
    fn items_builder(
        &mut self,
        builder: &Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>,
    ) {
        self.state_mut().builder = Some(builder.clone());
    }
}

impl Template for ComboBoxItem {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("ComboBoxItem")
            .style("combo_box_item")
            .min_width(64)
            .height(24)
            .selected(false)
            .pressed(false)
            .padding(0)
            .background("transparent")
            .border_radius(0)
            .border_width(0)
            .border_brush("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(32)
            .font("Roboto-Regular")
            .child(
                MouseBehavior::new()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .build(ctx),
            )
            .on_click(move |states, _| {
                states.get::<ComboBoxItemState>(id).toggle_selection();
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        Box::new(RectangleRenderObject)
    }

    fn layout(&self) -> Box<dyn Layout> {
        Box::new(PaddingLayout::new())
    }
}

/// The `ComboBoxState` is used to manipulate the position of the thumb of the slider widget.
#[derive(Default, AsAny)]
pub struct ComboBoxState {
    popup: Entity,
    action: Option<Action>,
    builder: Option<Arc<RefCell<dyn Fn(&mut BuildContext, usize) -> Entity + 'static>>>,
    count: usize,
    items_panel: Entity,
    selected_container: Entity,
}

impl ComboBoxState {
    fn action(&mut self, action: impl Into<Option<Action>>) {
        self.action = action.into();
    }

    // closes the popup on mouse up outside of the combobox and popup.
    fn close_popup(&mut self, ctx: &mut Context, p: Point) {
        let combo_box_position = ctx.widget().clone::<Point>("position");
        let combo_box_bounds = ctx.widget().clone::<Rectangle>("bounds");

        let combo_box_global_bounds = Rectangle::new(combo_box_position, combo_box_bounds.size());

        if !combo_box_global_bounds.contains(p) {
            ctx.widget().set("selected", false);
            ctx.widget().get_mut::<Selector>("selector").clear_state();
            ctx.get_widget(self.popup)
                .set("visibility", Visibility::Collapsed);
            ctx.get_widget(self.popup).update(false);
            ctx.widget().update(false);
        }
    }
}

impl State for ComboBoxState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        let count = ctx.widget().clone_or_default::<usize>("count");
        let entity = ctx.entity;

        // build the combobox items
        if count != self.count {
            if let Some(builder) = &self.builder {
                ctx.clear_children_of(self.items_panel);

                for i in 0..count {
                    let item = {
                        let build_context = &mut ctx.build_context();
                        let child = builder.borrow()(build_context, i);
                        let mut item = ComboBoxItem::new()
                            .index(i)
                            .combo_box(entity)
                            .selected_container(self.selected_container);

                        if let Some(builder) = &self.builder {
                            item.items_builder(builder);
                        }
                        let item = item.build(build_context);

                        let mouse_behavior =
                            MouseBehavior::new().target(item.0).build(build_context);
                        build_context.register_shared_property::<Selector>(
                            "selector",
                            mouse_behavior,
                            item,
                        );
                        build_context.register_shared_property::<bool>(
                            "pressed",
                            mouse_behavior,
                            item,
                        );
                        build_context.append_child(item, mouse_behavior);

                        build_context.register_shared_property::<Brush>("foreground", child, item);
                        build_context.register_shared_property::<f32>("opacity", item, entity);
                        build_context.register_shared_property::<f32>("opacity", child, entity);
                        build_context.register_shared_property::<f64>("font_size", child, item);
                        build_context.append_child(self.items_panel, item);
                        build_context.append_child(mouse_behavior, child);

                        item
                    };
                    ctx.get_widget(item).update_widget(entity, false, false);
                }
            }

            self.count = count;
        }
    }

    fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
        if self.action.is_none() || !(*ctx.widget().get::<bool>("selected")) {
            return;
        }

        if let Some(action) = self.action {
            match action {
                Action::CheckMouseUpOutside { position } => {
                    self.close_popup(ctx, position);
                }
            }
        }
    }

    fn cleanup(&mut self, _: &mut Registry, ctx: &mut Context) {
        let _ = ctx.remove_child_from_overlay(self.popup);
    }
}

// todo use code of list view item, by create combobox item insert entity of popup container

widget!(
    /// The `ComboBox` represents an selection widget with a drop-down list.
    ///
    /// **style:** `combo_box`
    ComboBox<ComboBoxState>: MouseHandler {
        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or share the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shared the count.
        count: usize,

        /// Sets or shares the selected index. If the value is -1 no item is selected.
        selected_index: i32,

        /// The entity of the selected item.
        selected_item: SelectedItem,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the pressed property.
        pressed: bool,

        /// Sets or shares the flag if the drop down is open.
        selected: bool,

        /// Sets or shares the icon property.
        icon: String,

        /// Sets or shares the icon brush property.
        icon_brush: Brush,

        /// Sets or share the icon font size property.
        icon_size: f64,

        /// Sets or shares the icon font property.
        icon_font: String
    }
);

impl ComboBox {
    /// Define the template build function for the content of the ComboBoxItems.
    pub fn items_builder<F: Fn(&mut BuildContext, usize) -> Entity + 'static + Clone>(
        mut self,
        builder: F,
    ) -> Self {
        self.state_mut().builder = Some(Arc::new(RefCell::new(builder)));
        self
    }
}

impl Template for ComboBox {
    fn template(mut self, id: Entity, ctx: &mut BuildContext) -> Self {
        let selected_container = Container::new().attach(Grid::column(0)).build(ctx);

        let container = Container::new()
            .id(CONTAINER)
            .background(id)
            .border_radius(id)
            .border_width(id)
            .border_brush(id)
            .padding(id)
            .child(
                Grid::new()
                    .columns(Columns::create().push("*").push(4.0).push(14.0))
                    .child(selected_container)
                    .child(
                        FontIconBlock::new()
                            .attach(Grid::column(2))
                            .v_align("center")
                            .icon_brush(id)
                            .icon_size(id)
                            .icon_font(id)
                            .icon(id)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .build(ctx);
        self.state_mut().selected_container = selected_container;

        let items_panel = Stack::new()
            .v_align("start")
            .id(ITEMS_PANEL)
            .orientation("vertical")
            .build(ctx);

        self.state_mut().items_panel = items_panel;
        let scroll_viewer = ScrollViewer::new()
            .mode(("disabled", "auto"))
            .child(items_panel)
            .build(ctx);

        let popup = Popup::new()
            .height(200.0)
            .open(("selected", id))
            .child(scroll_viewer)
            .child(
                ScrollIndicator::new()
                    .padding(2.0)
                    .content_bounds(("bounds", items_panel))
                    .view_port_bounds(("bounds", scroll_viewer))
                    .scroll_padding(("padding", scroll_viewer))
                    .mode(scroll_viewer)
                    .opacity(id)
                    .build(ctx),
            )
            .target(container.0)
            .build(ctx);
        self.state_mut().popup = popup;

        let _ = ctx.append_child_to_overlay(popup);

        self.name("ComboBox")
            .style("combo_box")
            .on_changed_filter(vec!["selected_item"])
            .icon(material_icons_font::MD_ARROW_DROP_DOWN)
            .icon_font("MaterialIcons-Regular")
            .icon_size(fonts::ICON_FONT_SIZE_12)
            .icon_brush(colors::LINK_WATER_COLOR)
            .height(32.0)
            .min_width(80.0)
            .selected(false)
            .selected_index(-1)
            .child(
                MouseBehavior::new()
                    .pressed(id)
                    .enabled(id)
                    .target(id.0)
                    .child(
                        SelectionBehavior::new()
                            .selected(id)
                            .enabled(id)
                            .target(id.0)
                            .child(container)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_global_mouse_up(move |states, e| {
                states
                    .get_mut::<ComboBoxState>(id)
                    .action(Action::CheckMouseUpOutside {
                        position: e.position,
                    })
            })
    }
}
<|endoftext|>


<commit_before>extern crate asn1_parse;
#[macro_use]
extern crate nom;
extern crate argparse;

use std::io;
use std::io::Read;
use std::fs;
use std::path::Path;
use asn1_parse::parse::spec::asn1_spec;
use argparse::{ArgumentParser, StoreOption};

fn main() {
  let opts = parse_args();

  let bytes: Result<Vec<_>, _> = match opts.file {
    Some(ref p) => io::BufReader::new(
      fs::File::open(Path::new(p)).unwrap()
    ).bytes().collect(),
    None => io::stdin().bytes().collect(),
  };
  let buffer = bytes.unwrap();
  let elems: nom::IResult<_, _> = many0!(buffer.as_slice(), complete!(asn1_spec));
  println!("{:#?}", elems);
}

struct ProgOpts {
  file: Option<String>,
}

fn parse_args() -> ProgOpts {
  let mut opts = ProgOpts {
    file: None,
  };

  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Dump ASN.1 specification files");
    ap.refer(&mut opts.file)
      .add_argument("file", StoreOption, "ASN.1 spec file to dump");
    ap.parse_args_or_exit();
  }
  opts
}
<commit_msg>Remove many0! from dump util, so errors get reported<commit_after>extern crate asn1_parse;
extern crate nom;
extern crate argparse;

use std::io;
use std::io::Read;
use std::fs;
use std::path::Path;
use asn1_parse::parse::spec::asn1_spec;
use argparse::{ArgumentParser, StoreOption};

fn main() {
  let opts = parse_args();

  let bytes: Result<Vec<_>, _> = match opts.file {
    Some(ref p) => io::BufReader::new(
      fs::File::open(Path::new(p)).unwrap()
    ).bytes().collect(),
    None => io::stdin().bytes().collect(),
  };
  let buffer = bytes.unwrap();
  let elems: nom::IResult<_, _> = asn1_spec(buffer.as_slice());
  println!("{:#?}", elems);
}

struct ProgOpts {
  file: Option<String>,
}

fn parse_args() -> ProgOpts {
  let mut opts = ProgOpts {
    file: None,
  };

  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Dump ASN.1 specification files");
    ap.refer(&mut opts.file)
      .add_argument("file", StoreOption, "ASN.1 spec file to dump");
    ap.parse_args_or_exit();
  }
  opts
}
<|endoftext|>


<commit_before>use std::cmp::min;
use std::io::prelude::*;
use std::io;
use common;

#[derive(Default)]
pub struct Day2 {
}

impl Day2 {

    pub fn new() -> Day2 {
        Default::default()
    }
}

impl common::Solution for Day2 {

    fn part1(&mut self, input: &mut io::Read) -> String {
        let reader = io::BufReader::new(input);
        let mut pos = 5;
        let mut code = String::new();

        for line in reader.lines() {
            for instruction in line.unwrap().trim().chars() {
                pos = move_pos1(pos, instruction);
            }
            code += &pos.to_string();
        }

        code
    }

    fn part2(&mut self, input: &mut io::Read) -> String {
        let reader = io::BufReader::new(input);
        let mut pos = (0, 2);
        let mut code = String::new();

        for line in reader.lines() {
            for instruction in line.unwrap().trim().chars() {
                pos = move_pos2(pos, instruction);
            }
            code += &pos2char(pos);
        }

        code
    }
}

fn move_pos1(pos: i32, instruction: char) -> i32
{
    match instruction {
        'U' => if pos > 3 { pos - 3 } else { pos },
        'D' => if pos < 7 { pos + 3 } else { pos },
        'L' => if pos % 3 != 1 { pos - 1 } else { pos },
        'R' => if pos % 3 != 0 { pos + 1 } else { pos },
        _   => panic!("Unsupported direction {}", instruction),
    }
}

fn row_width(y: i32) -> i32
{
    min(2 * y + 1, 9 - 2 * y)
}

fn row_offset(y: i32) -> i32
{
    (5 - row_width(y)) / 2
}

fn is_legal(pos: (i32, i32)) -> bool {
    let (x, y) = pos;
    let width = row_width(y);
    let offset = row_offset(y);

    y >= 0 && y < 5 && x >= offset && x < offset + width
}

fn move_pos2(pos: (i32, i32), instruction: char) -> (i32, i32)
{
    let (x, y) = pos;
    let new_pos = match instruction {
        'U' => (x, y - 1),
        'D' => (x, y + 1),
        'L' => (x - 1, y),
        'R' => (x + 1, y),
        _   => panic!("Unsupported direction {}", instruction),
    };

    if is_legal(new_pos) { new_pos } else { pos }
}

fn pos2char(pos: (i32, i32)) -> String
{
    let (x, y) = pos;
    let mut num = x + 1 - row_offset(y);
    for i in 0..y {
        num += row_width(i);
    }

    format!("{:X}", num)
}

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

    const SAMPLE: &str = "ULL
RRDDD
LURDL
UUUUD";

    #[test]
    fn test_part1() {
        let mut instance = Day2::new();
        assert_eq!("1985", instance.part1(&mut SAMPLE.as_bytes()));
    }

    #[test]
    fn test_part2() {
        let mut instance = Day2::new();
        assert_eq!("5DB3", instance.part2(&mut SAMPLE.as_bytes()));
    }

}
<commit_msg>Clean up tests<commit_after>use std::cmp::min;
use std::io::prelude::*;
use std::io;
use common;

#[derive(Default)]
pub struct Day2 {
}

impl Day2 {

    pub fn new() -> Day2 {
        Default::default()
    }
}

impl common::Solution for Day2 {

    fn part1(&mut self, input: &mut io::Read) -> String {
        let reader = io::BufReader::new(input);
        let mut pos = 5;
        let mut code = String::new();

        for line in reader.lines() {
            for instruction in line.unwrap().trim().chars() {
                pos = move_pos1(pos, instruction);
            }
            code += &pos.to_string();
        }

        code
    }

    fn part2(&mut self, input: &mut io::Read) -> String {
        let reader = io::BufReader::new(input);
        let mut pos = (0, 2);
        let mut code = String::new();

        for line in reader.lines() {
            for instruction in line.unwrap().trim().chars() {
                pos = move_pos2(pos, instruction);
            }
            code += &pos2char(pos);
        }

        code
    }
}

fn move_pos1(pos: i32, instruction: char) -> i32
{
    match instruction {
        'U' => if pos > 3 { pos - 3 } else { pos },
        'D' => if pos < 7 { pos + 3 } else { pos },
        'L' => if pos % 3 != 1 { pos - 1 } else { pos },
        'R' => if pos % 3 != 0 { pos + 1 } else { pos },
        _   => panic!("Unsupported direction {}", instruction),
    }
}

fn row_width(y: i32) -> i32
{
    min(2 * y + 1, 9 - 2 * y)
}

fn row_offset(y: i32) -> i32
{
    (5 - row_width(y)) / 2
}

fn is_legal(pos: (i32, i32)) -> bool {
    let (x, y) = pos;
    let width = row_width(y);
    let offset = row_offset(y);

    y >= 0 && y < 5 && x >= offset && x < offset + width
}

fn move_pos2(pos: (i32, i32), instruction: char) -> (i32, i32)
{
    let (x, y) = pos;
    let new_pos = match instruction {
        'U' => (x, y - 1),
        'D' => (x, y + 1),
        'L' => (x - 1, y),
        'R' => (x + 1, y),
        _   => panic!("Unsupported direction {}", instruction),
    };

    if is_legal(new_pos) { new_pos } else { pos }
}

fn pos2char(pos: (i32, i32)) -> String
{
    let (x, y) = pos;
    let mut num = x + 1 - row_offset(y);
    for i in 0..y {
        num += row_width(i);
    }

    format!("{:X}", num)
}

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

    const SAMPLE: &[u8] = b"ULL
RRDDD
LURDL
UUUUD";

    #[test]
    fn test_part1() {
        let mut instance = Day2::new();
        assert_eq!("1985", instance.part1(&mut SAMPLE));
    }

    #[test]
    fn test_part2() {
        let mut instance = Day2::new();
        assert_eq!("5DB3", instance.part2(&mut SAMPLE));
    }

}
<|endoftext|>


<commit_before>use gmp::mpq::Mpq;
use std::borrow::Borrow;
use std::collections::VecDeque;
use std::vec::Vec;

struct BallotState {
    visited: bool,
    prev: usize,
    edge_flow: Box<[Mpq]>,
    count: i32,
}

#[derive(Clone)]
struct CandidateState {
    prev: (usize, usize),
    count: i32,
}

pub fn strength<Ballot>(num_seats: usize, ballots: &[(Ballot, Mpq)]) -> Mpq
    where Ballot: Borrow<[usize]>
{
    let candidate_ballots = &mut vec![Vec::new(); num_seats][..];
    for (b, &(ref cs, _)) in ballots.iter().enumerate() {
        for (i, &c) in cs.borrow().iter().enumerate() {
            candidate_ballots[c].push((b, i));
        }
    }
    let ballot_states = &mut ballots.iter()
        .map(|&(ref cs, ref w)| {
            let mut edge_flow = vec![Mpq::zero(); 1 + cs.borrow().len()].into_boxed_slice();
            edge_flow[0] = w.clone();
            BallotState {
                visited: false,
                prev: !0,
                edge_flow: edge_flow,
                count: 0,
            }
        })
        .collect::<Vec<_>>()[..];
    let candidate_states = &mut vec![CandidateState {
        prev: (!0, !0),
        count: 0,
    }; num_seats][..];

    let mut total_flow = Mpq::zero();
    let mut queue = VecDeque::new();

    loop {
        for (b, bs) in ballot_states.iter_mut().enumerate() {
            if !bs.edge_flow[0].is_zero() {
                bs.visited = true;
                bs.prev = 0;
                queue.push_back(b);
            }
        }

        let mut found = Vec::new();
        'search: loop {
            match queue.pop_front() {
                None => {
                    return total_flow;
                }
                Some(b) => {
                    let (ref cs, _) = ballots[b];
                    for (i, &c) in cs.borrow().iter().enumerate() {
                        if candidate_states[c].prev != (!0, !0) {
                            continue;
                        }
                        candidate_states[c].prev = (b, i);
                        found.push(c);
                        if found.len() == num_seats {
                            break 'search;
                        }
                        for &(b1, i1) in &candidate_ballots[c] {
                            if ballot_states[b1].edge_flow[i1 + 1].is_zero() ||
                               ballot_states[b1].visited {
                                continue;
                            }
                            ballot_states[b1].visited = true;
                            ballot_states[b1].prev = i1 + 1;
                            queue.push_back(b1);
                        }
                    }
                }
            }
        }

        let mut sunk = 0;
        for &c in found.iter().rev() {
            let (b, _) = candidate_states[c].prev;
            let count = candidate_states[c].count + 1;
            ballot_states[b].count += count;
            let i1 = ballot_states[b].prev;
            if i1 == 0 {
                sunk += count;
            } else {
                let (ref cs, _) = ballots[b];
                candidate_states[cs.borrow()[i1 - 1]].count += count;
            }
        }
        debug_assert_eq!(sunk, num_seats as i32);

        let flow = found.iter()
            .map(|&c| {
                let (b, _) = candidate_states[c].prev;
                &ballot_states[b].edge_flow[ballot_states[b].prev] /
                Mpq::from(ballot_states[b].count as i64)
            })
            .min()
            .unwrap();
        debug_assert!(!flow.is_zero());
        total_flow = total_flow + &flow;

        for c in found {
            let (b, i) = candidate_states[c].prev;
            {
                let edge_flow = &mut ballot_states[b].edge_flow[i + 1];
                *edge_flow = &*edge_flow + &flow * Mpq::from(candidate_states[c].count as i64 + 1);
            }
            if ballot_states[b].count != 0 {
                let edge_flow = &mut ballot_states[b].edge_flow[ballot_states[b].prev];
                *edge_flow = &*edge_flow - &flow * Mpq::from(ballot_states[b].count as i64);
                ballot_states[b].count = 0;
            }

            candidate_states[c].prev = (!0, !0);
            candidate_states[c].count = 0;
        }

        for bs in &mut *ballot_states {
            bs.visited = false;
            bs.prev = !0;
            debug_assert_eq!(bs.count, 0);
        }
        queue.clear();
    }
}

#[cfg(test)]
mod tests {
    use super::strength;
    use gmp::mpq::Mpq;

    const Q: fn(i64) -> Mpq = Mpq::from;

    #[test]
    fn test_strength_1() {
        // Wikipedia
        let ballots: &[(&[usize], Mpq)] =
            &[(&[0], Q(12)), (&[1], Q(0)), (&[0, 1], Q(51)), (&[], Q(27))];
        assert_eq!(strength(2, ballots), Q(63) / Q(2));
    }

    #[test]
    fn test_strength_2() {
        // Wikipedia
        let ballots: &[(&[usize], Mpq)] = &[(&[0], Q(38)), (&[1], Q(27)), (&[0, 1], Q(12))];
        assert_eq!(strength(2, ballots), Q(77) / Q(2));
    }

    #[test]
    fn test_strength_3() {
        // Schulze’s calcul02.pdf
        let ballots: &[(&[usize], Mpq)] = &[(&[0, 1, 2, 3], Q(36_597383) / Q(1_000000)),
                                            (&[0, 1, 2], Q(5_481150) / Q(1_000000)),
                                            (&[0, 1, 3], Q(13_279131) / Q(1_000000)),
                                            (&[0, 1], Q(4_859413) / Q(1_000000)),
                                            (&[0, 2, 3], Q(35_425375) / Q(1_000000)),
                                            (&[0, 2], Q(5_490934) / Q(1_000000)),
                                            (&[0, 3], Q(22_855333) / Q(1_000000)),
                                            (&[0], Q(19_835570) / Q(1_000000)),
                                            (&[1, 2, 3], Q(22_928716) / Q(1_000000)),
                                            (&[1, 2], Q(5_538309) / Q(1_000000)),
                                            (&[1, 3], Q(13_130227) / Q(1_000000)),
                                            (&[1], Q(6_056291) / Q(1_000000)),
                                            (&[2, 3], Q(23_992772) / Q(1_000000)),
                                            (&[2], Q(16_699207) / Q(1_000000)),
                                            (&[3], Q(98_165759) / Q(1_000000)),
                                            (&[], Q(129_664430) / Q(1_000000))];
        assert_eq!(strength(4, ballots), Q(77_389937) / Q(1_000000));
    }
}
<commit_msg>vote_management: BallotState no longer needs a visited flag<commit_after>use gmp::mpq::Mpq;
use std::borrow::Borrow;
use std::collections::VecDeque;
use std::vec::Vec;

struct BallotState {
    prev: usize,
    edge_flow: Box<[Mpq]>,
    count: i32,
}

#[derive(Clone)]
struct CandidateState {
    prev: (usize, usize),
    count: i32,
}

pub fn strength<Ballot>(num_seats: usize, ballots: &[(Ballot, Mpq)]) -> Mpq
    where Ballot: Borrow<[usize]>
{
    let candidate_ballots = &mut vec![Vec::new(); num_seats][..];
    for (b, &(ref cs, _)) in ballots.iter().enumerate() {
        for (i, &c) in cs.borrow().iter().enumerate() {
            candidate_ballots[c].push((b, i));
        }
    }
    let ballot_states = &mut ballots.iter()
        .map(|&(ref cs, ref w)| {
            let mut edge_flow = vec![Mpq::zero(); 1 + cs.borrow().len()].into_boxed_slice();
            edge_flow[0] = w.clone();
            BallotState {
                prev: !0,
                edge_flow: edge_flow,
                count: 0,
            }
        })
        .collect::<Vec<_>>()[..];
    let candidate_states = &mut vec![CandidateState {
        prev: (!0, !0),
        count: 0,
    }; num_seats][..];

    let mut total_flow = Mpq::zero();
    let mut queue = VecDeque::new();

    loop {
        for (b, bs) in ballot_states.iter_mut().enumerate() {
            if !bs.edge_flow[0].is_zero() {
                bs.prev = 0;
                queue.push_back(b);
            }
        }

        let mut found = Vec::new();
        'search: loop {
            match queue.pop_front() {
                None => {
                    return total_flow;
                }
                Some(b) => {
                    let (ref cs, _) = ballots[b];
                    for (i, &c) in cs.borrow().iter().enumerate() {
                        if candidate_states[c].prev != (!0, !0) {
                            continue;
                        }
                        candidate_states[c].prev = (b, i);
                        found.push(c);
                        if found.len() == num_seats {
                            break 'search;
                        }
                        for &(b1, i1) in &candidate_ballots[c] {
                            if ballot_states[b1].edge_flow[i1 + 1].is_zero() ||
                               ballot_states[b1].prev != !0 {
                                continue;
                            }
                            ballot_states[b1].prev = i1 + 1;
                            queue.push_back(b1);
                        }
                    }
                }
            }
        }

        let mut sunk = 0;
        for &c in found.iter().rev() {
            let (b, _) = candidate_states[c].prev;
            let count = candidate_states[c].count + 1;
            ballot_states[b].count += count;
            let i1 = ballot_states[b].prev;
            if i1 == 0 {
                sunk += count;
            } else {
                let (ref cs, _) = ballots[b];
                candidate_states[cs.borrow()[i1 - 1]].count += count;
            }
        }
        debug_assert_eq!(sunk, num_seats as i32);

        let flow = found.iter()
            .map(|&c| {
                let (b, _) = candidate_states[c].prev;
                &ballot_states[b].edge_flow[ballot_states[b].prev] /
                Mpq::from(ballot_states[b].count as i64)
            })
            .min()
            .unwrap();
        debug_assert!(!flow.is_zero());
        total_flow = total_flow + &flow;

        for c in found {
            let (b, i) = candidate_states[c].prev;
            {
                let edge_flow = &mut ballot_states[b].edge_flow[i + 1];
                *edge_flow = &*edge_flow + &flow * Mpq::from(candidate_states[c].count as i64 + 1);
            }
            if ballot_states[b].count != 0 {
                let edge_flow = &mut ballot_states[b].edge_flow[ballot_states[b].prev];
                *edge_flow = &*edge_flow - &flow * Mpq::from(ballot_states[b].count as i64);
                ballot_states[b].count = 0;
            }

            candidate_states[c].prev = (!0, !0);
            candidate_states[c].count = 0;
        }

        for bs in &mut *ballot_states {
            bs.prev = !0;
            debug_assert_eq!(bs.count, 0);
        }
        queue.clear();
    }
}

#[cfg(test)]
mod tests {
    use super::strength;
    use gmp::mpq::Mpq;

    const Q: fn(i64) -> Mpq = Mpq::from;

    #[test]
    fn test_strength_1() {
        // Wikipedia
        let ballots: &[(&[usize], Mpq)] =
            &[(&[0], Q(12)), (&[1], Q(0)), (&[0, 1], Q(51)), (&[], Q(27))];
        assert_eq!(strength(2, ballots), Q(63) / Q(2));
    }

    #[test]
    fn test_strength_2() {
        // Wikipedia
        let ballots: &[(&[usize], Mpq)] = &[(&[0], Q(38)), (&[1], Q(27)), (&[0, 1], Q(12))];
        assert_eq!(strength(2, ballots), Q(77) / Q(2));
    }

    #[test]
    fn test_strength_3() {
        // Schulze’s calcul02.pdf
        let ballots: &[(&[usize], Mpq)] = &[(&[0, 1, 2, 3], Q(36_597383) / Q(1_000000)),
                                            (&[0, 1, 2], Q(5_481150) / Q(1_000000)),
                                            (&[0, 1, 3], Q(13_279131) / Q(1_000000)),
                                            (&[0, 1], Q(4_859413) / Q(1_000000)),
                                            (&[0, 2, 3], Q(35_425375) / Q(1_000000)),
                                            (&[0, 2], Q(5_490934) / Q(1_000000)),
                                            (&[0, 3], Q(22_855333) / Q(1_000000)),
                                            (&[0], Q(19_835570) / Q(1_000000)),
                                            (&[1, 2, 3], Q(22_928716) / Q(1_000000)),
                                            (&[1, 2], Q(5_538309) / Q(1_000000)),
                                            (&[1, 3], Q(13_130227) / Q(1_000000)),
                                            (&[1], Q(6_056291) / Q(1_000000)),
                                            (&[2, 3], Q(23_992772) / Q(1_000000)),
                                            (&[2], Q(16_699207) / Q(1_000000)),
                                            (&[3], Q(98_165759) / Q(1_000000)),
                                            (&[], Q(129_664430) / Q(1_000000))];
        assert_eq!(strength(4, ballots), Q(77_389937) / Q(1_000000));
    }
}
<|endoftext|>