<commit_before>/*!

DC (Distance Coding) forward and backward transformation.
Designed to be used on BWT block output for compression.

# Links

http://www.data-compression.info/Algorithms/DC/

# Example

```rust
use compress::bwt::dc;

let bytes = bytes!("abracadabra");
let (alphabet,distances) = dc::encode_simple::<uint>(bytes);
let decoded = dc::decode_simple(bytes.len(),
                                alphabet.as_slice(),
                                distances.as_slice());
```

# Credit

This is an original implementation.
Thanks to Edgar Binder for inventing DC!

*/

use std::io;
use vec = std::slice;
use super::mtf::MTF;

pub type Symbol = u8;
pub type Rank = u8;
pub static TotalSymbols: uint = 0x100;

/// encode a block of bytes 'input'
/// write output distance stream into 'distances'
/// return: unique bytes encountered in the order they appear
/// with the corresponding initial distances
pub fn encode<D: Clone + Eq + NumCast>(input: &[Symbol], distances: &mut [D], mtf: &mut MTF) -> ~[(Symbol,D)] {
    let n = input.len();
    assert_eq!(distances.len(), n);
    let mut last = [n, ..TotalSymbols];
    let mut unique: ~[(Symbol,D)] = ~[];
    let filler: D = NumCast::from(n).unwrap();
    for (i,&sym) in input.iter().enumerate() {
        distances[i] = filler.clone();
        let base = last[sym as uint];
        last[sym as uint] = i;
        debug!("\tProcessing symbol {} at position {}, last known at {}", sym, i, base);
        if base == n {
            let rank = unique.len();
            mtf.symbols[rank] = sym;
            mtf.encode(sym);    //==rank
            // initial distances are not ordered to support re-shuffle
            debug!("\t\tUnique => assigning rank {}, encoding {}", rank, i);
            let d = NumCast::from(i).unwrap();
            unique.push((sym,d));
        }else {
            let rank = mtf.encode(sym) as uint;
            if rank > 0 {
                debug!("\t\tRegular at rank {}, encoding {}", rank, i-base-rank-1);
                assert!(i >= base+rank+1);
                distances[base] = NumCast::from(i-base-rank-1).unwrap();
            }
        }
    }
    for (rank,&sym) in mtf.symbols.slice_to(unique.len()).iter().enumerate() {
        let base = last[sym as uint];
        debug!("\tSweep symbol {} of rank {}, last known at {}, encoding {}", sym, rank, base, n-base-rank-1);
        assert!(n >= base+rank+1);
        distances[base] = NumCast::from(n-base-rank-1).unwrap();
    }
    assert_eq!(input.iter().zip(input.iter().skip(1)).zip(distances.iter()).
        position(|((&a,&b),d)| *d==filler && a!=b), None);
    unique
}

/// encode with "batteries included" for quick testing
pub fn encode_simple<D: Clone + Eq + NumCast>(input: &[Symbol]) -> (~[Symbol],~[D]) {
    let n = input.len();
    if n==0 {
        (~[],~[])
    }else   {
        let mut raw_dist: ~[D] = vec::from_elem(n, NumCast::from(0).unwrap());
        let pairs = encode(input, raw_dist, &mut MTF::new());
        let symbols: ~[Symbol] = pairs.iter().map(|&(sym,_)| sym).collect();
        let init_iter = pairs.iter().map(|pair| { let (_, ref d) = *pair; d.clone() });
        let filler: D = NumCast::from(n).unwrap();
        // chain initial distances with intermediate ones
        let raw_iter = raw_dist.iter().filter_map(|d| if *d!=filler {Some(d.clone())} else {None});
        let mut combined = init_iter.chain(raw_iter);
        (symbols, combined.collect())
    }
}

/// Decode a block of distances with a list of initial symbols
pub fn decode(alphabet: Option<&[Symbol]>, output: &mut [Symbol], mtf: &mut MTF,
        fn_dist: |Symbol|->io::IoResult<uint>) -> io::IoResult<()> {
    let n = output.len();
    let mut next = [n, ..TotalSymbols];
    let alphabet_size = match alphabet  {
        Some([]) => {
            // alphabet is empty
            assert_eq!(n,0);
            return Ok(())
        },
        Some([sym]) => {
            // there is only one known symbol
            for out in output.mut_iter()    {
                *out = sym;
            }
            return Ok(())
        }
        Some(list) => {
            // given fixed alphabet
            for (rank,&sym) in list.iter().enumerate()   {
                // initial distances are not ordered
                next[sym as uint] = match fn_dist(sym) {
                    Ok(d) => d, // + (rank as Distance)
                    Err(e) => return Err(e)
                };
                mtf.symbols[rank] = sym;
                debug!("\tRegistering symbol {} of rank {} at position {}", sym, rank, next[sym as uint]);
            }
            for rank in range(list.len(),TotalSymbols) {
                mtf.symbols[rank] = 0; //erazing unused symbols
            }
            list.len()
        },
        None => {
            // alphabet is large, total range of symbols is assumed
            for i in range(0,TotalSymbols) {
                next[i] = match fn_dist(i as Symbol) {
                    Ok(d) => d,
                    Err(e) => return Err(e)
                };
                mtf.symbols[i] = i as Symbol;
                debug!("\tRegistering symbol {} at position {}", i, next[i]);
            }
            // sort ranks by first occurrence
            mtf.symbols.mut_slice_to(TotalSymbols).sort_by(|&a,&b| next[a as uint].cmp(&next[b as uint]));
            TotalSymbols
        },
    };
    let mut i = 0u;
    while i<n {
        let sym = mtf.symbols[0];
        let stop = next[mtf.symbols[1] as uint];
        debug!("\tFilling region [{}-{}) with symbol {}", i, stop, sym);
        while i<stop    {
            output[i] = sym;
            i += 1;
        }
        let future = match fn_dist(sym) {
            Ok(d) => stop + d,
            Err(e) => return Err(e)
        };
        debug!("\t\tLooking for future position {}", future);
        assert!(future <= n);
        let mut rank = 1u;
        while rank < alphabet_size && future+rank > next[mtf.symbols[rank] as uint] {
            mtf.symbols[rank-1] = mtf.symbols[rank];
            rank += 1;
        }
        if rank < alphabet_size {
            debug!("\t\tFound sym {} of rank {} at position {}", mtf.symbols[rank],
                rank, next[mtf.symbols[rank] as uint]);
        }else {
            debug!("\t\tNot found");
        }
        mtf.symbols[rank-1] = sym;
        debug!("\t\tAssigning future pos {} for symbol {}", future+rank-1, sym);
        next[sym as uint] = future+rank-1;
    }
    assert_eq!(next.iter().position(|&d| d<n || d>=n+alphabet_size), None);
    assert_eq!(i, n);
    Ok(())
}

/// decode with "batteries included" for quick testing
pub fn decode_simple<D: ToPrimitive>(n: uint, alphabet: &[Symbol], distances: &[D]) -> ~[Symbol] {
    let mut output = vec::from_elem(n, 0 as Symbol);
    let mut di = 0u;
    decode(Some(alphabet), output.as_mut_slice(), &mut MTF::new(), |_sym| {
        di += 1;
        if di > distances.len() {
            Err(io::standard_error(io::EndOfFile))
        }else {
            Ok(distances[di-1].to_uint().unwrap())
        }
    }).unwrap();
    output
}

#[cfg(test)]
mod test {
    use std;

    fn roundtrip(bytes: &[u8]) {
        info!("Roundtrip DC of size {}", bytes.len());
        let (alphabet,distances) = super::encode_simple::<uint>(bytes);
        debug!("Roundtrip DC input: {:?}, alphabet: {:?}, distances: {:?}", bytes, alphabet, distances);
        let decoded = super::decode_simple(bytes.len(), alphabet.as_slice(), distances.as_slice());
        assert_eq!(decoded.as_slice(), bytes);
    }

    fn roundtrip_full_alphabet(bytes: &[u8]) {
        let n = bytes.len();
        info!("Roundtrip DC (full alphabet) of size {}", n);
        let mut mtf = super::MTF::new();
        // encoding with full alphabet
        let mut raw_dist = std::slice::from_elem(n, 0u);
        let pairs = super::encode(bytes, raw_dist, &mut mtf);
        let mut alphabet = std::slice::from_elem(0x100, n);
        for &(sym,dist) in pairs.iter() {
            alphabet[sym as uint] = dist;
        }
        let raw_iter = raw_dist.iter().filter(|&d| *d!=n);
        let distances: ~[&uint] = alphabet.iter().chain(raw_iter).collect();
        // decoding with full alphabet
        let mut decoded = std::slice::from_elem(n, 0 as super::Symbol);
        let mut di = 0u;
        super::decode(None, decoded.as_mut_slice(), &mut mtf, |_sym| {
            di += 1;
            Ok(distances[di-1].to_uint().unwrap())
        }).unwrap();
        // comparing with input
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn roundtrips_short() {
        roundtrip(bytes!("teeesst_dc"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("../data/test.txt"));
    }

    #[test]
    fn roundtrips_long() {
        let input: ~[u8] = std::iter::range_inclusive(0u8, 0xFFu8).collect();
        roundtrip_full_alphabet(input);
    }
}
<commit_msg>DC - added a full distance context<commit_after>/*!

DC (Distance Coding) forward and backward transformation.
Designed to be used on BWT block output for compression.

# Links

http://www.data-compression.info/Algorithms/DC/

# Example

```rust
use compress::bwt::dc;

let bytes = bytes!("abracadabra");
let (alphabet,distances) = dc::encode_simple::<uint>(bytes);
let decoded = dc::decode_simple(bytes.len(),
                                alphabet.as_slice(),
                                distances.as_slice());
```

# Credit

This is an original implementation.
Thanks to Edgar Binder for inventing DC!

*/

use std::io;
use vec = std::slice;
use super::mtf::MTF;

pub type Symbol = u8;
pub type Rank = u8;
pub static TotalSymbols: uint = 0x100;

/// Distance coding context
pub struct Context<D> {
    /// current symbol
    symbol: Symbol,
    /// last known MTF rank
    last_rank: Option<Rank>,
    /// maximum possible distance
    distance_limit: D,
}

impl<D> Context<D> {
    /// create a new distance context
    pub fn new(s: Symbol, r: Option<Rank>, d: D) -> Context<D> {
        Context {
            symbol: s,
            last_rank: r,
            distance_limit: d,
        }
    }
}

/// encode a block of bytes 'input'
/// write output distance stream into 'distances'
/// return: unique bytes encountered in the order they appear
/// with the corresponding initial distances
pub fn encode<D: Clone + Eq + NumCast>(input: &[Symbol], distances: &mut [D], mtf: &mut MTF) -> ~[(Symbol,D)] {
    let n = input.len();
    assert_eq!(distances.len(), n);
    let mut last = [n, ..TotalSymbols];
    let mut unique: ~[(Symbol,D)] = ~[];
    let filler: D = NumCast::from(n).unwrap();
    for (i,&sym) in input.iter().enumerate() {
        distances[i] = filler.clone();
        let base = last[sym as uint];
        last[sym as uint] = i;
        debug!("\tProcessing symbol {} at position {}, last known at {}", sym, i, base);
        if base == n {
            let rank = unique.len();
            mtf.symbols[rank] = sym;
            mtf.encode(sym);    //==rank
            // initial distances are not ordered to support re-shuffle
            debug!("\t\tUnique => assigning rank {}, encoding {}", rank, i);
            let d = NumCast::from(i).unwrap();
            unique.push((sym,d));
        }else {
            let rank = mtf.encode(sym) as uint;
            if rank > 0 {
                debug!("\t\tRegular at rank {}, encoding {}", rank, i-base-rank-1);
                assert!(i >= base+rank+1);
                distances[base] = NumCast::from(i-base-rank-1).unwrap();
            }
        }
    }
    for (rank,&sym) in mtf.symbols.slice_to(unique.len()).iter().enumerate() {
        let base = last[sym as uint];
        debug!("\tSweep symbol {} of rank {}, last known at {}, encoding {}", sym, rank, base, n-base-rank-1);
        assert!(n >= base+rank+1);
        distances[base] = NumCast::from(n-base-rank-1).unwrap();
    }
    assert_eq!(input.iter().zip(input.iter().skip(1)).zip(distances.iter()).
        position(|((&a,&b),d)| *d==filler && a!=b), None);
    unique
}

/// encode with "batteries included" for quick testing
pub fn encode_simple<D: Clone + Eq + NumCast>(input: &[Symbol]) -> (~[Symbol],~[D]) {
    let n = input.len();
    if n==0 {
        (~[],~[])
    }else   {
        let mut raw_dist: ~[D] = vec::from_elem(n, NumCast::from(0).unwrap());
        let pairs = encode(input, raw_dist, &mut MTF::new());
        let symbols: ~[Symbol] = pairs.iter().map(|&(sym,_)| sym).collect();
        let init_iter = pairs.iter().map(|pair| { let (_, ref d) = *pair; d.clone() });
        let filler: D = NumCast::from(n).unwrap();
        // chain initial distances with intermediate ones
        let raw_iter = raw_dist.iter().filter_map(|d| if *d!=filler {Some(d.clone())} else {None});
        let mut combined = init_iter.chain(raw_iter);
        (symbols, combined.collect())
    }
}

/// Decode a block of distances with a list of initial symbols
pub fn decode(alphabet: Option<&[Symbol]>, output: &mut [Symbol], mtf: &mut MTF,
        fn_dist: |&Context<uint>|->io::IoResult<uint>) -> io::IoResult<()> {
    let n = output.len();
    let mut next = [n, ..TotalSymbols];
    let mut ranks = [0 as Rank, ..TotalSymbols];
    let alphabet_size = match alphabet  {
        Some([]) => {
            // alphabet is empty
            assert_eq!(n, 0);
            return Ok(())
        },
        Some([sym]) => {
            // there is only one known symbol
            for out in output.mut_iter()    {
                *out = sym;
            }
            return Ok(())
        }
        Some(list) => {
            // given fixed alphabet
            for (rank,&sym) in list.iter().enumerate()   {
                let ctx = Context::new(sym, None, n);
                // initial distances are not ordered
                next[sym] = match fn_dist(&ctx) {
                    Ok(d) => d, // + (rank as Distance)
                    Err(e) => return Err(e)
                };
                mtf.symbols[rank] = sym;
                debug!("\tRegistering symbol {} of rank {} at position {}", sym, rank, next[sym as uint]);
            }
            for rank in range(list.len(),TotalSymbols) {
                mtf.symbols[rank] = 0; //erazing unused symbols
            }
            list.len()
        },
        None => {
            // alphabet is large, total range of symbols is assumed
            for i in range(0,TotalSymbols) {
                let sym = i as Symbol;
                let ctx = Context::new(sym, None, n);
                next[i] = match fn_dist(&ctx) {
                    Ok(d) => d,
                    Err(e) => return Err(e)
                };
                mtf.symbols[i] = sym;
                ranks[sym] = i as Rank;
                debug!("\tRegistering symbol {} at position {}", i, next[i]);
            }
            // sort ranks by first occurrence
            mtf.symbols.mut_slice_to(TotalSymbols).sort_by(|&a,&b| next[a as uint].cmp(&next[b as uint]));
            TotalSymbols
        },
    };
    let mut i = 0u;
    while i<n {
        let sym = mtf.symbols[0];
        let stop = next[mtf.symbols[1] as uint];
        debug!("\tFilling region [{}-{}) with symbol {}", i, stop, sym);
        while i<stop    {
            output[i] = sym;
            i += 1;
        }
        let ctx = Context::new(sym, Some(ranks[sym]), n-i);
        let future = match fn_dist(&ctx) {
            Ok(d) => stop + d,
            Err(e) => return Err(e)
        };
        debug!("\t\tLooking for future position {}", future);
        assert!(future <= n);
        let mut rank = 1u;
        while rank < alphabet_size && future+rank > next[mtf.symbols[rank] as uint] {
            mtf.symbols[rank-1] = mtf.symbols[rank];
            rank += 1;
        }
        if rank < alphabet_size {
            debug!("\t\tFound sym {} of rank {} at position {}", mtf.symbols[rank],
                rank, next[mtf.symbols[rank] as uint]);
        }else {
            debug!("\t\tNot found");
        }
        mtf.symbols[rank-1] = sym;
        debug!("\t\tAssigning future pos {} for symbol {}", future+rank-1, sym);
        next[sym] = future+rank-1;
        ranks[sym] = rank as Rank;
    }
    assert_eq!(next.iter().position(|&d| d<n || d>=n+alphabet_size), None);
    assert_eq!(i, n);
    Ok(())
}

/// decode with "batteries included" for quick testing
pub fn decode_simple<D: ToPrimitive>(n: uint, alphabet: &[Symbol], distances: &[D]) -> ~[Symbol] {
    let mut output = vec::from_elem(n, 0 as Symbol);
    let mut di = 0u;
    decode(Some(alphabet), output.as_mut_slice(), &mut MTF::new(), |_ctx| {
        di += 1;
        if di > distances.len() {
            Err(io::standard_error(io::EndOfFile))
        }else {
            Ok(distances[di-1].to_uint().unwrap())
        }
    }).unwrap();
    output
}

#[cfg(test)]
mod test {
    use std;

    fn roundtrip(bytes: &[u8]) {
        info!("Roundtrip DC of size {}", bytes.len());
        let (alphabet,distances) = super::encode_simple::<uint>(bytes);
        debug!("Roundtrip DC input: {:?}, alphabet: {:?}, distances: {:?}", bytes, alphabet, distances);
        let decoded = super::decode_simple(bytes.len(), alphabet.as_slice(), distances.as_slice());
        assert_eq!(decoded.as_slice(), bytes);
    }

    fn roundtrip_full_alphabet(bytes: &[u8]) {
        let n = bytes.len();
        info!("Roundtrip DC (full alphabet) of size {}", n);
        let mut mtf = super::MTF::new();
        // encoding with full alphabet
        let mut raw_dist = std::slice::from_elem(n, 0u);
        let pairs = super::encode(bytes, raw_dist, &mut mtf);
        let mut alphabet = std::slice::from_elem(0x100, n);
        for &(sym,dist) in pairs.iter() {
            alphabet[sym as uint] = dist;
        }
        let raw_iter = raw_dist.iter().filter(|&d| *d!=n);
        let distances: ~[&uint] = alphabet.iter().chain(raw_iter).collect();
        // decoding with full alphabet
        let mut decoded = std::slice::from_elem(n, 0 as super::Symbol);
        let mut di = 0u;
        super::decode(None, decoded.as_mut_slice(), &mut mtf, |_sym| {
            di += 1;
            Ok(distances[di-1].to_uint().unwrap())
        }).unwrap();
        // comparing with input
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn roundtrips_short() {
        roundtrip(bytes!("teeesst_dc"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("../data/test.txt"));
    }

    #[test]
    fn roundtrips_long() {
        let input: ~[u8] = std::iter::range_inclusive(0u8, 0xFFu8).collect();
        roundtrip_full_alphabet(input);
    }
}
<|endoftext|>


<commit_before>/*!

DC (Distance Coding) forward and backward transformation.
Designed to be used on BWT block output for compression.

# Links

http://www.data-compression.info/Algorithms/DC/

# Example

```rust
use compress::bwt::dc;

let bytes = bytes!("abracadabra");
let (alphabet,distances) = dc::encode_simple::<uint>(bytes);
let decoded = dc::decode_simple(bytes.len(),
                                alphabet.as_slice(),
                                distances.as_slice());
```

# Credit

This is an original implementation.
Thanks to Edgar Binder for inventing DC!

*/

use std::io;
use vec = std::slice;
use super::mtf::MTF;

pub type Symbol = u8;
pub type Rank = u8;
pub static TotalSymbols: uint = 0x100;

/// Distance coding context
/// Has all the information potentially needed by the underlying coding model
pub struct Context<D> {
    /// current symbol
    symbol: Symbol,
    /// last known MTF rank
    last_rank: Option<Rank>,
    /// maximum possible distance
    distance_limit: D,
}

impl<D> Context<D> {
    /// create a new distance context
    pub fn new(s: Symbol, r: Option<Rank>, d: D) -> Context<D> {
        Context {
            symbol: s,
            last_rank: r,
            distance_limit: d,
        }
    }
}

/// encode a block of bytes 'input'
/// write output distance stream into 'distances'
/// return: unique bytes encountered in the order they appear
/// with the corresponding initial distances
pub fn encode<D: Clone + Eq + NumCast>(input: &[Symbol], distances: &mut [D], mtf: &mut MTF) -> ~[(Symbol,D)] {
    let n = input.len();
    assert_eq!(distances.len(), n);
    let mut last = [n, ..TotalSymbols];
    let mut unique: ~[(Symbol,D)] = vec::with_capacity(TotalSymbols);
    let filler: D = NumCast::from(n).unwrap();
    for (i,&sym) in input.iter().enumerate() {
        distances[i] = filler.clone();
        let base = last[sym as uint];
        last[sym as uint] = i;
        debug!("\tProcessing symbol {} at position {}, last known at {}", sym, i, base);
        if base == n {
            let rank = unique.len();
            mtf.symbols[rank] = sym;
            mtf.encode(sym);    //==rank
            // initial distances are not ordered to support re-shuffle
            debug!("\t\tUnique => assigning rank {}, encoding {}", rank, i);
            let d = NumCast::from(i).unwrap();
            unique.push((sym,d));
        }else {
            let rank = mtf.encode(sym) as uint;
            if rank > 0 {
                debug!("\t\tRegular at rank {}, encoding {}", rank, i-base-rank-1);
                assert!(i >= base+rank+1);
                distances[base] = NumCast::from(i-base-rank-1).unwrap();
            }
        }
    }
    for (rank,&sym) in mtf.symbols.slice_to(unique.len()).iter().enumerate() {
        let base = last[sym as uint];
        debug!("\tSweep symbol {} of rank {}, last known at {}, encoding {}", sym, rank, base, n-base-rank-1);
        assert!(n >= base+rank+1);
        distances[base] = NumCast::from(n-base-rank-1).unwrap();
    }
    assert_eq!(input.iter().zip(input.iter().skip(1)).zip(distances.iter()).
        position(|((&a,&b),d)| *d==filler && a!=b), None);
    unique
}

/// encode with "batteries included" for quick testing
pub fn encode_simple<D: Clone + Eq + NumCast>(input: &[Symbol]) -> (~[Symbol],~[D]) {
    let n = input.len();
    if n==0 {
        (~[],~[])
    }else   {
        let mut raw_dist: ~[D] = vec::from_elem(n, NumCast::from(0).unwrap());
        let pairs = encode(input, raw_dist, &mut MTF::new());
        let mut symbols = pairs.iter().map(|&(sym,_)| sym);
        let init_iter = pairs.iter().map(|pair| { let (_, ref d) = *pair; d.clone() });
        let filler: D = NumCast::from(n).unwrap();
        // chain initial distances with intermediate ones
        let raw_iter = raw_dist.iter().filter_map(|d| if *d!=filler {Some(d.clone())} else {None});
        let mut combined = init_iter.chain(raw_iter);
        (symbols.collect(), combined.collect())
    }
}

/// Decode a block of distances given initial symbol distances
pub fn decode_body(mut next: [uint,..TotalSymbols], output: &mut [Symbol], mtf: &mut MTF,
        fn_dist: |Context<uint>|->io::IoResult<uint>) -> io::IoResult<()> {

    let n = output.len();
    let mut i = 0u;
    for (sym,d) in next.iter().enumerate() {
        if *d < n {
            let mut j = i;
            while j>0u && next[mtf.symbols[j-1] as uint] > *d {
                mtf.symbols[j] = mtf.symbols[j-1];
                j -= 1;
            }
            mtf.symbols[j] = sym as Symbol;
            i += 1;
        }
    }
    if i<=1 {
        // redundant alphabet case
        let sym = mtf.symbols[0];
        for out in output.mut_iter()    {
            *out = sym;
        }
        return Ok(())
    }

    let alphabet_size = i;
    let mut ranks = [0 as Rank, ..TotalSymbols];
    for rank in range(0, i) {
        let sym = mtf.symbols[rank];
        debug!("\tRegistering symbol {} of rank {} at position {}",
            sym, rank, next[sym as uint]);
        ranks[sym as uint] = rank as Rank;
    }

    i = 0u;
    while i<n {
        let sym = mtf.symbols[0];
        let stop = next[mtf.symbols[1] as uint];
        debug!("\tFilling region [{}-{}) with symbol {}", i, stop, sym);
        while i<stop    {
            output[i] = sym;
            i += 1;
        }
        let ctx = Context::new(sym, Some(ranks[sym as uint]), n-i);
        let future = match fn_dist(ctx) {
            Ok(d) => stop + d,
            Err(e) => return Err(e)
        };
        debug!("\t\tLooking for future position {}", future);
        assert!(future <= n);
        let mut rank = 1u;
        while rank < alphabet_size && future+rank > next[mtf.symbols[rank] as uint] {
            mtf.symbols[rank-1] = mtf.symbols[rank];
            rank += 1;
        }
        if rank < alphabet_size {
            debug!("\t\tFound sym {} of rank {} at position {}", mtf.symbols[rank],
                rank, next[mtf.symbols[rank] as uint]);
        }else {
            debug!("\t\tNot found");
        }
        mtf.symbols[rank-1] = sym;
        debug!("\t\tAssigning future pos {} for symbol {}", future+rank-1, sym);
        next[sym as uint] = future+rank-1;
        ranks[sym as uint] = rank as Rank;
    }
    assert_eq!(next.iter().position(|&d| d<n || d>=n+alphabet_size), None);
    assert_eq!(i, n);
    Ok(())
}

/// Decode a block of distances with a list of initial symbols
pub fn decode(alphabet: Option<&[Symbol]>, output: &mut [Symbol], mtf: &mut MTF,
    fn_dist: |Context<uint>|->io::IoResult<uint>) -> io::IoResult<()> {

    let n = output.len();
    let mut next = [n, ..TotalSymbols];
    match alphabet {
        Some(list) => {
            // given fixed alphabet
            for &sym in list.iter() {
                let ctx = Context::new(sym, None, n);
                // initial distances are not ordered
                next[sym as uint] = match fn_dist(ctx) {
                    Ok(d) => d, // + (rank as Distance)
                    Err(e) => return Err(e)
                };
            }
        },
        None => {
            // alphabet is large, total range of symbols is assumed
            for i in range(0, TotalSymbols) {
                let ctx = Context::new(i as Symbol, None, n);
                next[i] = match fn_dist(ctx) {
                    Ok(d) => d,
                    Err(e) => return Err(e)
                };
            }
        },
    }

    decode_body(next, output, mtf, fn_dist)
}

/// decode with "batteries included" for quick testing
pub fn decode_simple<D: ToPrimitive>(n: uint, alphabet: &[Symbol], distances: &[D]) -> ~[Symbol] {
    let mut output = vec::from_elem(n, 0 as Symbol);
    let mut di = 0u;
    decode(Some(alphabet), output.as_mut_slice(), &mut MTF::new(), |_ctx| {
        di += 1;
        if di > distances.len() {
            Err(io::standard_error(io::EndOfFile))
        }else {
            Ok(distances[di-1].to_uint().unwrap())
        }
    }).unwrap();
    output
}

#[cfg(test)]
mod test {
    use std;

    fn roundtrip(bytes: &[u8]) {
        info!("Roundtrip DC of size {}", bytes.len());
        let (alphabet,distances) = super::encode_simple::<uint>(bytes);
        debug!("Roundtrip DC input: {:?}, alphabet: {:?}, distances: {:?}", bytes, alphabet, distances);
        let decoded = super::decode_simple(bytes.len(), alphabet.as_slice(), distances.as_slice());
        assert_eq!(decoded.as_slice(), bytes);
    }

    fn roundtrip_full_alphabet(bytes: &[u8]) {
        let n = bytes.len();
        info!("Roundtrip DC (full alphabet) of size {}", n);
        let mut mtf = super::MTF::new();
        // encoding with full alphabet
        let mut raw_dist = std::slice::from_elem(n, 0u);
        let pairs = super::encode(bytes, raw_dist, &mut mtf);
        let mut alphabet = std::slice::from_elem(0x100, n);
        for &(sym,dist) in pairs.iter() {
            alphabet[sym as uint] = dist;
        }
        let raw_iter = raw_dist.iter().filter(|&d| *d!=n);
        let distances: ~[&uint] = alphabet.iter().chain(raw_iter).collect();
        // decoding with full alphabet
        let mut decoded = std::slice::from_elem(n, 0 as super::Symbol);
        let mut di = 0u;
        super::decode(None, decoded.as_mut_slice(), &mut mtf, |_sym| {
            di += 1;
            Ok(distances[di-1].to_uint().unwrap())
        }).unwrap();
        // comparing with input
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn roundtrips_short() {
        roundtrip(bytes!("teeesst_dc"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("../data/test.txt"));
    }

    #[test]
    fn roundtrips_long() {
        let input: ~[u8] = std::iter::range_inclusive(0u8, 0xFFu8).collect();
        roundtrip_full_alphabet(input);
    }
}
<commit_msg>DC - Encode iterator added<commit_after>/*!

DC (Distance Coding) forward and backward transformation.
Designed to be used on BWT block output for compression.

# Links

http://www.data-compression.info/Algorithms/DC/

# Example

```rust
use compress::bwt::dc;

let bytes = bytes!("abracadabra");
let (alphabet,distances) = dc::encode_simple::<uint>(bytes);
let decoded = dc::decode_simple(bytes.len(),
                                alphabet.as_slice(),
                                distances.as_slice());
```

# Credit

This is an original implementation.
Thanks to Edgar Binder for inventing DC!

*/

use std::{io, iter};
use vec = std::slice;
use super::mtf::MTF;

pub type Symbol = u8;
pub type Rank = u8;
pub static TotalSymbols: uint = 0x100;

/// Distance coding context
/// Has all the information potentially needed by the underlying coding model
pub struct Context {
    /// current symbol
    symbol: Symbol,
    /// last known MTF rank
    last_rank: Rank,
    /// maximum possible distance
    distance_limit: uint,
}

impl Context {
    /// create a new distance context
    pub fn new(s: Symbol, r: Rank, dmax: uint) -> Context {
        Context {
            symbol: s,
            last_rank: r,
            distance_limit: dmax,
        }
    }
}

/// DC body iterator, can be used to encode distances
pub struct EncodeIterator<'a,'b,D> {
    data: iter::Enumerate<iter::Zip<vec::Items<'a,Symbol>,vec::Items<'b,D>>>,
    pos: [uint, ..TotalSymbols],
    size: uint,
}

impl<'a, 'b, D: NumCast> EncodeIterator<'a,'b,D> {
    /// fixme
    pub fn new(input: &'a [Symbol], dist: &'b [D], next: &[D, ..TotalSymbols]) -> EncodeIterator<'a,'b,D> {
        assert_eq!(input.len(), dist.len());
        let mut pos = [0u, ..TotalSymbols];
        for (pi,ni) in pos.mut_iter().zip(next.iter()) {
            *pi = ni.to_uint().unwrap();
        }
        EncodeIterator {
            data: input.iter().zip(dist.iter()).enumerate(),
            pos: pos,
            size: input.len()
        }
    }
}

impl<'a, 'b, D: Clone + Eq + NumCast> Iterator<(D,Context)> for EncodeIterator<'a,'b,D> {
    fn next(&mut self) -> Option<(D,Context)> {
        let filler: D = NumCast::from(self.size).unwrap();
        self.data.find(|&(_,(_,d))| *d != filler).map(|(i,(sym,d))| {
            let rank = i - self.pos[*sym as uint];
            assert!(0<rank && rank<TotalSymbols);
            self.pos[*sym as uint] = i + d.to_uint().unwrap();
            (d.clone(), Context::new(*sym, rank as Rank, self.size-i))
        })
    }
}

/// encode a block of bytes 'input'
/// write output distance stream into 'distances'
/// return: unique bytes encountered in the order they appear
/// with the corresponding initial distances
pub fn encode<'a, 'b, D: Clone + Eq + NumCast>(input: &'a [Symbol], distances: &'b mut [D], mtf: &mut MTF) -> ~[(Symbol,D)] {
    let n = input.len();
    assert_eq!(distances.len(), n);
    let mut last = [n, ..TotalSymbols];
    let mut unique: ~[(Symbol,D)] = vec::with_capacity(TotalSymbols);
    let filler: D = NumCast::from(n).unwrap();
    for (i,&sym) in input.iter().enumerate() {
        distances[i] = filler.clone();
        let base = last[sym as uint];
        last[sym as uint] = i;
        debug!("\tProcessing symbol {} at position {}, last known at {}", sym, i, base);
        if base == n {
            let rank = unique.len();
            mtf.symbols[rank] = sym;
            mtf.encode(sym);    //==rank
            // initial distances are not ordered to support re-shuffle
            debug!("\t\tUnique => assigning rank {}, encoding {}", rank, i);
            let d = NumCast::from(i).unwrap();
            unique.push((sym,d));
        }else {
            let rank = mtf.encode(sym) as uint;
            if rank > 0 {
                debug!("\t\tRegular at rank {}, encoding {}", rank, i-base-rank-1);
                assert!(i >= base+rank+1);
                distances[base] = NumCast::from(i-base-rank-1).unwrap();
            }
        }
    }
    for (rank,&sym) in mtf.symbols.slice_to(unique.len()).iter().enumerate() {
        let base = last[sym as uint];
        debug!("\tSweep symbol {} of rank {}, last known at {}, encoding {}", sym, rank, base, n-base-rank-1);
        assert!(n >= base+rank+1);
        distances[base] = NumCast::from(n-base-rank-1).unwrap();
    }
    assert_eq!(input.iter().zip(input.iter().skip(1)).zip(distances.iter()).
        position(|((&a,&b),d)| *d==filler && a!=b), None);
    unique
}

/// encode with "batteries included" for quick testing
pub fn encode_simple<D: Clone + Eq + NumCast>(input: &[Symbol]) -> (~[Symbol],~[D]) {
    let n = input.len();
    if n==0 {
        (~[],~[])
    }else   {
        let mut raw_dist: ~[D] = vec::from_elem(n, NumCast::from(0).unwrap());
        let pairs = encode(input, raw_dist, &mut MTF::new());
        let mut symbols = pairs.iter().map(|&(sym,_)| sym);
        let init_iter = pairs.iter().map(|pair| { let (_, ref d) = *pair; d.clone() });
        let filler: D = NumCast::from(n).unwrap();
        // chain initial distances with intermediate ones
        let raw_iter = raw_dist.iter().filter_map(|d| if *d!=filler {Some(d.clone())} else {None});
        let mut combined = init_iter.chain(raw_iter);
        (symbols.collect(), combined.collect())
    }
}

/// Decode a block of distances given initial symbol distances
pub fn decode_body(mut next: [uint,..TotalSymbols], output: &mut [Symbol], mtf: &mut MTF,
        fn_dist: |Context|->io::IoResult<uint>) -> io::IoResult<()> {

    let n = output.len();
    let mut i = 0u;
    for (sym,d) in next.iter().enumerate() {
        if *d < n {
            let mut j = i;
            while j>0u && next[mtf.symbols[j-1] as uint] > *d {
                mtf.symbols[j] = mtf.symbols[j-1];
                j -= 1;
            }
            mtf.symbols[j] = sym as Symbol;
            i += 1;
        }
    }
    if i<=1 {
        // redundant alphabet case
        let sym = mtf.symbols[0];
        for out in output.mut_iter()    {
            *out = sym;
        }
        return Ok(())
    }

    let alphabet_size = i;
    let mut ranks = [0 as Rank, ..TotalSymbols];
    for rank in range(0, i) {
        let sym = mtf.symbols[rank];
        debug!("\tRegistering symbol {} of rank {} at position {}",
            sym, rank, next[sym as uint]);
        ranks[sym as uint] = rank as Rank;
    }

    i = 0u;
    while i<n {
        let sym = mtf.symbols[0];
        let stop = next[mtf.symbols[1] as uint];
        debug!("\tFilling region [{}-{}) with symbol {}", i, stop, sym);
        while i<stop    {
            output[i] = sym;
            i += 1;
        }
        let ctx = Context::new(sym, ranks[sym as uint], n-i);
        let future = match fn_dist(ctx) {
            Ok(d) => stop + d,
            Err(e) => return Err(e)
        };
        debug!("\t\tLooking for future position {}", future);
        assert!(future <= n);
        let mut rank = 1u;
        while rank < alphabet_size && future+rank > next[mtf.symbols[rank] as uint] {
            mtf.symbols[rank-1] = mtf.symbols[rank];
            rank += 1;
        }
        if rank < alphabet_size {
            debug!("\t\tFound sym {} of rank {} at position {}", mtf.symbols[rank],
                rank, next[mtf.symbols[rank] as uint]);
        }else {
            debug!("\t\tNot found");
        }
        mtf.symbols[rank-1] = sym;
        debug!("\t\tAssigning future pos {} for symbol {}", future+rank-1, sym);
        next[sym as uint] = future+rank-1;
        ranks[sym as uint] = rank as Rank;
    }
    assert_eq!(next.iter().position(|&d| d<n || d>=n+alphabet_size), None);
    assert_eq!(i, n);
    Ok(())
}

/// Decode a block of distances with a list of initial symbols
pub fn decode(alphabet: Option<&[Symbol]>, output: &mut [Symbol], mtf: &mut MTF,
    fn_dist: |Context|->io::IoResult<uint>) -> io::IoResult<()> {

    let n = output.len();
    let mut next = [n, ..TotalSymbols];
    match alphabet {
        Some(list) => {
            // given fixed alphabet
            for &sym in list.iter() {
                let ctx = Context::new(sym, 0, n);
                // initial distances are not ordered
                next[sym as uint] = match fn_dist(ctx) {
                    Ok(d) => d, // + (rank as Distance)
                    Err(e) => return Err(e)
                };
            }
        },
        None => {
            // alphabet is large, total range of symbols is assumed
            for i in range(0, TotalSymbols) {
                let ctx = Context::new(i as Symbol, 9, n);
                next[i] = match fn_dist(ctx) {
                    Ok(d) => d,
                    Err(e) => return Err(e)
                };
            }
        },
    }

    decode_body(next, output, mtf, fn_dist)
}

/// decode with "batteries included" for quick testing
pub fn decode_simple<D: ToPrimitive>(n: uint, alphabet: &[Symbol], distances: &[D]) -> ~[Symbol] {
    let mut output = vec::from_elem(n, 0 as Symbol);
    let mut di = 0u;
    decode(Some(alphabet), output.as_mut_slice(), &mut MTF::new(), |_ctx| {
        di += 1;
        if di > distances.len() {
            Err(io::standard_error(io::EndOfFile))
        }else {
            Ok(distances[di-1].to_uint().unwrap())
        }
    }).unwrap();
    output
}

#[cfg(test)]
mod test {
    use std;

    fn roundtrip(bytes: &[u8]) {
        info!("Roundtrip DC of size {}", bytes.len());
        let (alphabet,distances) = super::encode_simple::<uint>(bytes);
        debug!("Roundtrip DC input: {:?}, alphabet: {:?}, distances: {:?}", bytes, alphabet, distances);
        let decoded = super::decode_simple(bytes.len(), alphabet.as_slice(), distances.as_slice());
        assert_eq!(decoded.as_slice(), bytes);
    }

    fn roundtrip_full_alphabet(bytes: &[u8]) {
        let n = bytes.len();
        info!("Roundtrip DC (full alphabet) of size {}", n);
        let mut mtf = super::MTF::new();
        // encoding with full alphabet
        let mut raw_dist = std::slice::from_elem(n, 0u);
        let pairs = super::encode(bytes, raw_dist, &mut mtf);
        let mut alphabet = std::slice::from_elem(0x100, n);
        for &(sym,dist) in pairs.iter() {
            alphabet[sym as uint] = dist;
        }
        let raw_iter = raw_dist.iter().filter(|&d| *d!=n);
        let distances: ~[&uint] = alphabet.iter().chain(raw_iter).collect();
        // decoding with full alphabet
        let mut decoded = std::slice::from_elem(n, 0 as super::Symbol);
        let mut di = 0u;
        super::decode(None, decoded.as_mut_slice(), &mut mtf, |_sym| {
            di += 1;
            Ok(distances[di-1].to_uint().unwrap())
        }).unwrap();
        // comparing with input
        assert_eq!(decoded.as_slice(), bytes);
    }

    #[test]
    fn roundtrips_short() {
        roundtrip(bytes!("teeesst_dc"));
        roundtrip(bytes!(""));
        roundtrip(include_bin!("../data/test.txt"));
    }

    #[test]
    fn roundtrips_long() {
        let input: ~[u8] = std::iter::range_inclusive(0u8, 0xFFu8).collect();
        roundtrip_full_alphabet(input);
    }
}
<|endoftext|>


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

// compile-flags: -Z parse-only

enum X {
    A =
        b'a' //~ ERROR discriminator values can only be used with a c-like enum
    ,
    B(isize)
}

fn main() {}
<commit_msg>Update issue-17383.rs<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -Z parse-only

enum X {
    A =
        b'a' //~ ERROR discriminator values can only be used with a field-less enum
    ,
    B(isize)
}

fn main() {}
<|endoftext|>


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

// https://leetcode.com/problems/number-of-people-aware-of-a-secret/
pub fn people_aware_of_secret(n: i32, delay: i32, forget: i32) -> i32 {
    let mut answer: i64 = if 1 + forget > n { 1 } else { 0 };
    let mut list: LinkedList<i32> = LinkedList::new();
    list.push_back(1);
    loop {
        let front = list.pop_front();
        match front {
            Some(day) => {
                if day > n {
                    break;
                }
                let secret_day = day + delay;
                for d in secret_day..(secret_day + (forget - delay)) {
                    if d > n {
                        break;
                    }
                    list.push_back(d);
                    if d + forget > n {
                        answer += 1;
                    }
                }
            }
            None => break,
        }
    }
    (answer & 1_000_000_007) as i32
}

fn main() {
    // println!("{}", people_aware_of_secret(6, 2, 4)); // 5
    // println!("{}", people_aware_of_secret(4, 1, 3)); // 6
    // println!("{}", people_aware_of_secret(10, 3, 5)); // 5
    println!("{}", people_aware_of_secret(1000, 500, 600)); // 100
}
<commit_msg>Update problem 2327<commit_after>use std::collections::LinkedList;

// https://leetcode.com/problems/number-of-people-aware-of-a-secret/
pub fn people_aware_of_secret(n: i32, delay: i32, forget: i32) -> i32 {
    let mut answer: i64 = if 1 + forget > n { 1 } else { 0 };
    let mut list: LinkedList<i32> = LinkedList::new();
    list.push_back(1);
    loop {
        let front = list.pop_front();
        match front {
            Some(day) => {
                if day > n {
                    break;
                }
                let secret_day = day + delay;
                for d in secret_day..(secret_day + (forget - delay)) {
                    if d > n {
                        break;
                    }
                    list.push_back(d);
                    if d + forget > n {
                        answer += 1;
                    }
                }
            }
            None => break,
        }
    }
    (answer % 1_000_000_007) as i32
}

fn main() {
    // println!("{}", people_aware_of_secret(6, 2, 4)); // 5
    // println!("{}", people_aware_of_secret(4, 1, 3)); // 6
    // println!("{}", people_aware_of_secret(10, 3, 5)); // 5
    // println!("{}", people_aware_of_secret(1000, 500, 600)); // 100
    println!("{}", people_aware_of_secret(1000, 2, 1000)); // 517691607
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/number-of-subarrays-with-gcd-equal-to-k/
pub fn subarray_gcd(nums: Vec<i32>, k: i32) -> i32 {
    fn gcd(nums: &[i32]) -> i32 {
        fn f(a: i32, b: i32) -> i32 {
            if b == 0 {
                a
            } else {
                f(b, a % b)
            }
        }

        let mut result = nums[0];
        for i in 1..nums.len() {
            result = f(result, nums[i]);
        }
        result
    }

    let mut answer = 0;
    for i in 0..nums.len() {
        for j in i + 1..=nums.len() {
            if gcd(&nums[i..j]) == k {
                answer += 1;
            }
        }
    }
    answer
}

fn main() {
    println!("{}", subarray_gcd(vec![9, 3, 1, 2, 6, 3], 3)); // 4
    println!("{}", subarray_gcd(vec![4], 7)); // 0
    println!("{}", subarray_gcd(vec![9, 6, 3], 3)); // 4
    println!("{}", subarray_gcd(vec![2, 4, 6, 8, 16], 3)); // 4
    println!("{}", subarray_gcd(vec![2], 4)); // 0
    println!("{}", subarray_gcd(vec![6], 2)); // 0
    println!("{}", subarray_gcd(vec![9, 6], 3)); // 1
    println!("{}", subarray_gcd(vec![9, 3], 3)); // 2
}
<commit_msg>Solve problem 2447<commit_after>// https://leetcode.com/problems/number-of-subarrays-with-gcd-equal-to-k/
pub fn subarray_gcd(nums: Vec<i32>, k: i32) -> i32 {
    fn gcd(a: i32, b: i32) -> i32 {
        if b == 0 {
            a
        } else {
            gcd(b, a % b)
        }
    }

    let mut answer = 0;
    for i in 0..nums.len() {
        let mut result = nums[i];
        if result == k {
            answer += 1;
        }
        for j in i + 1..nums.len() {
            result = gcd(result, nums[j]);
            if result == k {
                answer += 1;
            }
        }
    }
    answer
}

fn main() {
    println!("{}", subarray_gcd(vec![9, 3, 1, 2, 6, 3], 3)); // 4
    println!("{}", subarray_gcd(vec![4], 7)); // 0
    println!("{}", subarray_gcd(vec![9, 6, 3], 3)); // 4
    println!("{}", subarray_gcd(vec![2, 4, 6, 8, 16], 3)); // 4
    println!("{}", subarray_gcd(vec![2], 4)); // 0
    println!("{}", subarray_gcd(vec![6], 2)); // 0
    println!("{}", subarray_gcd(vec![9, 6], 3)); // 1
    println!("{}", subarray_gcd(vec![9, 3], 3)); // 2
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The triangular distribution.

use rand::Rng;
use crate::{Distribution, Standard};

/// The triangular distribution.
///
/// A continuous probability distribution parameterised by a range, and a mode
/// (most likely value) within that range.
///
/// The probability density function is triangular. For a similar distribution
/// with a smooth PDF, see the [Pert] distribution.
///
/// # Example
///
/// ```rust
/// use rand_distr::{Triangular, Distribution};
///
/// let d = Triangular::new(0., 5., 2.5).unwrap();
/// let v = d.sample(&mut rand::thread_rng());
/// println!("{} is from a triangular distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Triangular {
    min: f64,
    max: f64,
    mode: f64,
}

/// Error type returned from [`Triangular::new`].
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TriangularError {
    /// `max < min` or `min` or `max` is NaN.
    RangeTooSmall,
    /// `mode < min` or `mode > max` or `mode` is NaN.
    ModeRange,
}

impl Triangular {
    /// Set up the Triangular distribution with defined `min`, `max` and `mode`.
    #[inline]
    pub fn new(min: f64, max: f64, mode: f64) -> Result<Triangular, TriangularError> {
        if !(max >= min) {
            return Err(TriangularError::RangeTooSmall);
        }
        if !(mode >= min && max >= mode) {
            return Err(TriangularError::ModeRange);
        }
        Ok(Triangular { min, max, mode })
    }
}

impl Distribution<f64> for Triangular {
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
        let f: f64 = rng.sample(Standard);
        let diff_mode_min = self.mode - self.min;
        let range = self.max - self.min;
        let f_range = f * range;
        if f_range < diff_mode_min {
            self.min + (f_range * diff_mode_min).sqrt()
        } else {
            self.max - ((range - f_range) * (self.max - self.mode)).sqrt()
        }
    }
}

#[cfg(test)]
mod test {
    use std::f64;
    use rand::{Rng, rngs::mock};
    use super::*;

    #[test]
    fn test_triangular() {
        let mut half_rng = mock::StepRng::new(0x8000_0000_0000_0000, 0);
        assert_eq!(half_rng.gen::<f64>(), 0.5);
        for &(min, max, mode, median) in &[
            (-1., 1., 0., 0.),
            (1., 2., 1., 2. - 0.5f64.sqrt()),
            (5., 25., 25., 5. + 200f64.sqrt()),
            (1e-5, 1e5, 1e-3, 1e5 - 4999999949.5f64.sqrt()),
            (0., 1., 0.9, 0.45f64.sqrt()),
            (-4., -0.5, -2., -4.0 + 3.5f64.sqrt()),
        ] {
            println!("{} {} {} {}", min, max, mode, median);
            let distr = Triangular::new(min, max, mode).unwrap();
            // Test correct value at median:
            assert_eq!(distr.sample(&mut half_rng), median);
        }

        for &(min, max, mode) in &[
            (-1., 1., 2.),
            (-1., 1., -2.),
            (2., 1., 1.),
        ] {
            assert!(Triangular::new(min, max, mode).is_err());
        }
    }

    #[test]
    fn test_triangular_vector() {
        let rng = crate::test::rng(860);
        let distr = Triangular::new(2., 10., 3.).unwrap();
        let seq = distr.sample_iter(rng).take(5).collect::<Vec<f64>>();
        println!("seq: {:?}", seq);
        let expected = vec![4.941640229082449, 2.421447306833011,
                4.5964271605527385, 2.789763631136542, 4.8014432067978445];
        assert!(seq == expected);
    }
}
<commit_msg>rand_distr: make Triangular generic over Float<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The triangular distribution.

use rand::Rng;
use crate::{Distribution, Standard};
use crate::utils::Float;

/// The triangular distribution.
///
/// A continuous probability distribution parameterised by a range, and a mode
/// (most likely value) within that range.
///
/// The probability density function is triangular. For a similar distribution
/// with a smooth PDF, see the [Pert] distribution.
///
/// # Example
///
/// ```rust
/// use rand_distr::{Triangular, Distribution};
///
/// let d = Triangular::new(0., 5., 2.5).unwrap();
/// let v = d.sample(&mut rand::thread_rng());
/// println!("{} is from a triangular distribution", v);
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Triangular<N> {
    min: N,
    max: N,
    mode: N,
}

/// Error type returned from [`Triangular::new`].
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TriangularError {
    /// `max < min` or `min` or `max` is NaN.
    RangeTooSmall,
    /// `mode < min` or `mode > max` or `mode` is NaN.
    ModeRange,
}

impl<N: Float> Triangular<N>
where Standard: Distribution<N>
{
    /// Set up the Triangular distribution with defined `min`, `max` and `mode`.
    #[inline]
    pub fn new(min: N, max: N, mode: N) -> Result<Triangular<N>, TriangularError> {
        if !(max >= min) {
            return Err(TriangularError::RangeTooSmall);
        }
        if !(mode >= min && max >= mode) {
            return Err(TriangularError::ModeRange);
        }
        Ok(Triangular { min, max, mode })
    }
}

impl<N: Float> Distribution<N> for Triangular<N>
where Standard: Distribution<N>
{
    #[inline]
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> N {
        let f: N = rng.sample(Standard);
        let diff_mode_min = self.mode - self.min;
        let range = self.max - self.min;
        let f_range = f * range;
        if f_range < diff_mode_min {
            self.min + (f_range * diff_mode_min).sqrt()
        } else {
            self.max - ((range - f_range) * (self.max - self.mode)).sqrt()
        }
    }
}

#[cfg(test)]
mod test {
    use std::f64;
    use rand::{Rng, rngs::mock};
    use super::*;

    #[test]
    fn test_triangular() {
        let mut half_rng = mock::StepRng::new(0x8000_0000_0000_0000, 0);
        assert_eq!(half_rng.gen::<f64>(), 0.5);
        for &(min, max, mode, median) in &[
            (-1., 1., 0., 0.),
            (1., 2., 1., 2. - 0.5f64.sqrt()),
            (5., 25., 25., 5. + 200f64.sqrt()),
            (1e-5, 1e5, 1e-3, 1e5 - 4999999949.5f64.sqrt()),
            (0., 1., 0.9, 0.45f64.sqrt()),
            (-4., -0.5, -2., -4.0 + 3.5f64.sqrt()),
        ] {
            println!("{} {} {} {}", min, max, mode, median);
            let distr = Triangular::new(min, max, mode).unwrap();
            // Test correct value at median:
            assert_eq!(distr.sample(&mut half_rng), median);
        }

        for &(min, max, mode) in &[
            (-1., 1., 2.),
            (-1., 1., -2.),
            (2., 1., 1.),
        ] {
            assert!(Triangular::new(min, max, mode).is_err());
        }
    }

    #[test]
    fn test_triangular_vector() {
        let rng = crate::test::rng(860);
        let distr = Triangular::new(2., 10., 3.).unwrap();
        let seq = distr.sample_iter(rng).take(5).collect::<Vec<f64>>();
        println!("seq: {:?}", seq);
        let expected = vec![4.941640229082449, 2.421447306833011,
                4.5964271605527385, 2.789763631136542, 4.8014432067978445];
        assert!(seq == expected);
    }
}
<|endoftext|>


<commit_before>/// Weather update server
/// Binds PUB socket to tcp://*:5556 and ipc://weather.ipc
/// Publishes random weather updates

extern crate zmq;

use std::rand::Rng;

fn main() {
    let mut context = zmq::Context::new();
    let mut publisher = context.socket(zmq::PUB).unwrap();

    assert!(publisher.bind("tcp://*:5556").is_ok());
    assert!(publisher.bind("ipc://weather.ipc").is_ok());

    let mut rng = std::rand::weak_rng();

    loop {
        let zipcode     = rng.gen_range::<int>(0, 100000);
        let temperature = rng.gen_range::<int>(-80, 135);
        let relhumidity = rng.gen_range::<int>(10, 60);

        // this is slower than C because the current format! implementation is
        // very, very slow. Several orders of magnitude slower than glibc's
        // sprintf
        let update = format!("{:05d} {:d} {:d}", zipcode, temperature, relhumidity);
        publisher.send(update.as_bytes(), 0).unwrap();
    }

    // note: destructors mean no explicit cleanup necessary
}
<commit_msg>Use new librand in weather-server example.<commit_after>/// Weather update server
/// Binds PUB socket to tcp://*:5556 and ipc://weather.ipc
/// Publishes random weather updates

extern crate zmq;
extern crate rand;

use rand::Rng;

fn main() {
    let mut context = zmq::Context::new();
    let mut publisher = context.socket(zmq::PUB).unwrap();

    assert!(publisher.bind("tcp://*:5556").is_ok());
    assert!(publisher.bind("ipc://weather.ipc").is_ok());

    let mut rng = rand::weak_rng();

    loop {
        let zipcode     = rng.gen_range(0, 100000);
        let temperature = rng.gen_range(-80, 135);
        let relhumidity = rng.gen_range(10, 60);

        // this is slower than C because the current format! implementation is
        // very, very slow. Several orders of magnitude slower than glibc's
        // sprintf
        let update = format!("{:05d} {:d} {:d}", zipcode, temperature, relhumidity);
        publisher.send(update.as_bytes(), 0).unwrap();
    }

    // note: destructors mean no explicit cleanup necessary
}
<|endoftext|>


<commit_before>//! Event callbacks.

use cairo::Context;
use gdk::{EventButton, EventMotion, EventScroll, EventCrossing, ScrollDirection, EventKey,
          keyval_from_name};
use gtk::{DrawingArea, Inhibit, WidgetExt};

use app::AppContextPointer;
use coords::{DeviceCoords, XYCoords};
use gui::plot_context::PlotContext;

mod drawing;

/// Draws the sounding, connected to the on-draw event signal.
pub fn draw_sounding(cr: &Context, ac: &AppContextPointer) -> Inhibit {

    let mut ac = ac.borrow_mut();

    drawing::prepare_to_draw(cr, &mut ac);
    drawing::draw_background(cr, &ac);
    drawing::draw_temperature_profiles(cr, &ac);
    drawing::draw_wind_profile(cr, &ac);
    drawing::draw_labels(cr, &ac);
    drawing::draw_active_sample(cr, &ac);

    Inhibit(false)
}

/// Handles zooming from the mouse wheel. Connected to the scroll-event signal.
pub fn scroll_event(
    _sounding_area: &DrawingArea,
    event: &EventScroll,
    ac: &AppContextPointer,
) -> Inhibit {

    const DELTA_SCALE: f64 = 1.05;
    const MIN_ZOOM: f64 = 1.0;
    const MAX_ZOOM: f64 = 10.0;

    let mut ac = ac.borrow_mut();

    let pos = ac.skew_t.convert_device_to_xy(
        DeviceCoords::from(event.get_position()),
    );
    let dir = event.get_direction();

    let old_zoom = ac.get_zoom_factor();
    let mut new_zoom = old_zoom;

    match dir {
        ScrollDirection::Up => {
            new_zoom *= DELTA_SCALE;
        }
        ScrollDirection::Down => {
            new_zoom /= DELTA_SCALE;
        }
        _ => {}
    }

    if new_zoom < MIN_ZOOM {
        new_zoom = MIN_ZOOM;
    } else if new_zoom > MAX_ZOOM {
        new_zoom = MAX_ZOOM;
    }
    ac.skew_t.set_zoom_factor(new_zoom);
    // ac.rh_omega.set_zoom_factor(new_zoom);

    let translate = ac.skew_t.get_translate();
    let translate_x = pos.x - old_zoom / new_zoom * (pos.x - translate.x);
    let translate_y = pos.y - old_zoom / new_zoom * (pos.y - translate.y);
    let translate = XYCoords {
        x: translate_x,
        y: translate_y,
    };
    ac.skew_t.set_translate(translate);

    // Bound the xy-coords to always be on screen.
    ac.skew_t.bound_view();
    let translate = ac.skew_t.get_translate();
    ac.rh_omega.set_translate_y(translate);

    ac.update_all_gui();

    Inhibit(true)
}

/// Handles button press events
pub fn button_press_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    ac: &AppContextPointer,
) -> Inhibit {

    // Left mouse button
    if event.get_button() == 1 {
        let mut ac = ac.borrow_mut();
        ac.skew_t.set_last_cursor_position(
            Some(event.get_position().into()),
        );
        ac.skew_t.set_left_button_pressed(true);
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles button release events
pub fn button_release_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    ac: &AppContextPointer,
) -> Inhibit {
    if event.get_button() == 1 {
        let mut ac = ac.borrow_mut();
        ac.skew_t.set_last_cursor_position(None);
        ac.skew_t.set_left_button_pressed(false);
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles leave notify
pub fn leave_event(
    _sounding_area: &DrawingArea,
    _event: &EventCrossing,
    ac: &AppContextPointer,
) -> Inhibit {
    let mut ac = ac.borrow_mut();

    ac.skew_t.set_last_cursor_position(None);
    ac.set_sample(None);
    ac.update_all_gui();

    Inhibit(false)
}

/// Handles motion events
pub fn mouse_motion_event(
    sounding_area: &DrawingArea,
    event: &EventMotion,
    ac: &AppContextPointer,
) -> Inhibit {

    sounding_area.grab_focus();

    let mut ac = ac.borrow_mut();
    if ac.skew_t.get_left_button_pressed() {
        if let Some(last_position) = ac.skew_t.get_last_cursor_position() {
            let old_position = ac.skew_t.convert_device_to_xy(last_position);
            let new_position = DeviceCoords::from(event.get_position());
            ac.skew_t.set_last_cursor_position(Some(new_position));

            let new_position = ac.skew_t.convert_device_to_xy(new_position);
            let delta = (
                new_position.x - old_position.x,
                new_position.y - old_position.y,
            );
            let mut translate = ac.skew_t.get_translate();
            translate.x -= delta.0;
            translate.y -= delta.1;
            ac.skew_t.set_translate(translate);

            // Bound the xy-coords to always be on screen.
            ac.skew_t.bound_view();
            let translate = ac.skew_t.get_translate();
            ac.rh_omega.set_translate_y(translate);

            ac.set_sample(None);
            ac.update_all_gui();
        }
    } else if ac.plottable() {
        let position: DeviceCoords = event.get_position().into();

        ac.skew_t.set_last_cursor_position(Some(position));
        let tp_position = ac.skew_t.convert_device_to_tp(position);
        let sample = ::sounding_analysis::linear_interpolate(
            ac.get_sounding_for_display().unwrap(), // ac.plottable() call ensures this won't panic
            tp_position.pressure,
        );
        ac.set_sample(Some(sample));
        ac.update_all_gui();
    }
    Inhibit(false)
}

/// Handles key-release events, display next or previous sounding in a series.
pub fn key_release_event(
    _sounding_area: &DrawingArea,
    _event: &EventKey,
    _ac: &AppContextPointer,
) -> Inhibit {
    Inhibit(false)
}

/// Handles key-press events
pub fn key_press_event(
    _sounding_area: &DrawingArea,
    event: &EventKey,
    ac: &AppContextPointer,
) -> Inhibit {

    let keyval = event.get_keyval();
    if keyval == keyval_from_name("Right") || keyval == keyval_from_name("KP_Right") {
        let mut ac = ac.borrow_mut();
        ac.display_next();
        Inhibit(true)
    } else if keyval == keyval_from_name("Left") || keyval == keyval_from_name("KP_Left") {
        let mut ac = ac.borrow_mut();
        ac.display_previous();
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}
<commit_msg>Change drawing order.<commit_after>//! Event callbacks.

use cairo::Context;
use gdk::{EventButton, EventMotion, EventScroll, EventCrossing, ScrollDirection, EventKey,
          keyval_from_name};
use gtk::{DrawingArea, Inhibit, WidgetExt};

use app::AppContextPointer;
use coords::{DeviceCoords, XYCoords};
use gui::plot_context::PlotContext;

mod drawing;

/// Draws the sounding, connected to the on-draw event signal.
pub fn draw_sounding(cr: &Context, ac: &AppContextPointer) -> Inhibit {

    let mut ac = ac.borrow_mut();

    drawing::prepare_to_draw(cr, &mut ac);
    drawing::draw_background(cr, &ac);
    drawing::draw_labels(cr, &ac);
    drawing::draw_temperature_profiles(cr, &ac);
    drawing::draw_wind_profile(cr, &ac);
    drawing::draw_active_sample(cr, &ac);

    Inhibit(false)
}

/// Handles zooming from the mouse wheel. Connected to the scroll-event signal.
pub fn scroll_event(
    _sounding_area: &DrawingArea,
    event: &EventScroll,
    ac: &AppContextPointer,
) -> Inhibit {

    const DELTA_SCALE: f64 = 1.05;
    const MIN_ZOOM: f64 = 1.0;
    const MAX_ZOOM: f64 = 10.0;

    let mut ac = ac.borrow_mut();

    let pos = ac.skew_t.convert_device_to_xy(
        DeviceCoords::from(event.get_position()),
    );
    let dir = event.get_direction();

    let old_zoom = ac.get_zoom_factor();
    let mut new_zoom = old_zoom;

    match dir {
        ScrollDirection::Up => {
            new_zoom *= DELTA_SCALE;
        }
        ScrollDirection::Down => {
            new_zoom /= DELTA_SCALE;
        }
        _ => {}
    }

    if new_zoom < MIN_ZOOM {
        new_zoom = MIN_ZOOM;
    } else if new_zoom > MAX_ZOOM {
        new_zoom = MAX_ZOOM;
    }
    ac.skew_t.set_zoom_factor(new_zoom);
    // ac.rh_omega.set_zoom_factor(new_zoom);

    let translate = ac.skew_t.get_translate();
    let translate_x = pos.x - old_zoom / new_zoom * (pos.x - translate.x);
    let translate_y = pos.y - old_zoom / new_zoom * (pos.y - translate.y);
    let translate = XYCoords {
        x: translate_x,
        y: translate_y,
    };
    ac.skew_t.set_translate(translate);

    // Bound the xy-coords to always be on screen.
    ac.skew_t.bound_view();
    let translate = ac.skew_t.get_translate();
    ac.rh_omega.set_translate_y(translate);

    ac.update_all_gui();

    Inhibit(true)
}

/// Handles button press events
pub fn button_press_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    ac: &AppContextPointer,
) -> Inhibit {

    // Left mouse button
    if event.get_button() == 1 {
        let mut ac = ac.borrow_mut();
        ac.skew_t.set_last_cursor_position(
            Some(event.get_position().into()),
        );
        ac.skew_t.set_left_button_pressed(true);
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles button release events
pub fn button_release_event(
    _sounding_area: &DrawingArea,
    event: &EventButton,
    ac: &AppContextPointer,
) -> Inhibit {
    if event.get_button() == 1 {
        let mut ac = ac.borrow_mut();
        ac.skew_t.set_last_cursor_position(None);
        ac.skew_t.set_left_button_pressed(false);
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}

/// Handles leave notify
pub fn leave_event(
    _sounding_area: &DrawingArea,
    _event: &EventCrossing,
    ac: &AppContextPointer,
) -> Inhibit {
    let mut ac = ac.borrow_mut();

    ac.skew_t.set_last_cursor_position(None);
    ac.set_sample(None);
    ac.update_all_gui();

    Inhibit(false)
}

/// Handles motion events
pub fn mouse_motion_event(
    sounding_area: &DrawingArea,
    event: &EventMotion,
    ac: &AppContextPointer,
) -> Inhibit {

    sounding_area.grab_focus();

    let mut ac = ac.borrow_mut();
    if ac.skew_t.get_left_button_pressed() {
        if let Some(last_position) = ac.skew_t.get_last_cursor_position() {
            let old_position = ac.skew_t.convert_device_to_xy(last_position);
            let new_position = DeviceCoords::from(event.get_position());
            ac.skew_t.set_last_cursor_position(Some(new_position));

            let new_position = ac.skew_t.convert_device_to_xy(new_position);
            let delta = (
                new_position.x - old_position.x,
                new_position.y - old_position.y,
            );
            let mut translate = ac.skew_t.get_translate();
            translate.x -= delta.0;
            translate.y -= delta.1;
            ac.skew_t.set_translate(translate);

            // Bound the xy-coords to always be on screen.
            ac.skew_t.bound_view();
            let translate = ac.skew_t.get_translate();
            ac.rh_omega.set_translate_y(translate);

            ac.set_sample(None);
            ac.update_all_gui();
        }
    } else if ac.plottable() {
        let position: DeviceCoords = event.get_position().into();

        ac.skew_t.set_last_cursor_position(Some(position));
        let tp_position = ac.skew_t.convert_device_to_tp(position);
        let sample = ::sounding_analysis::linear_interpolate(
            ac.get_sounding_for_display().unwrap(), // ac.plottable() call ensures this won't panic
            tp_position.pressure,
        );
        ac.set_sample(Some(sample));
        ac.update_all_gui();
    }
    Inhibit(false)
}

/// Handles key-release events, display next or previous sounding in a series.
pub fn key_release_event(
    _sounding_area: &DrawingArea,
    _event: &EventKey,
    _ac: &AppContextPointer,
) -> Inhibit {
    Inhibit(false)
}

/// Handles key-press events
pub fn key_press_event(
    _sounding_area: &DrawingArea,
    event: &EventKey,
    ac: &AppContextPointer,
) -> Inhibit {

    let keyval = event.get_keyval();
    if keyval == keyval_from_name("Right") || keyval == keyval_from_name("KP_Right") {
        let mut ac = ac.borrow_mut();
        ac.display_next();
        Inhibit(true)
    } else if keyval == keyval_from_name("Left") || keyval == keyval_from_name("KP_Left") {
        let mut ac = ac.borrow_mut();
        ac.display_previous();
        Inhibit(true)
    } else {
        Inhibit(false)
    }
}
<|endoftext|>


<commit_before>mod screen;

use self::screen::Screen;
use data::{Editable, Modifiable, Named, Selectable, Undoable};
use std::{cmp, iter};
use syntect::easy::HighlightLines;
use syntect::highlighting::Theme;
use syntect::highlighting::{Color, FontStyle, Style};
use syntect::parsing::{SyntaxReference, SyntaxSet};
use termion::terminal_size;
pub struct View<'a> {
    message: Option<String>,
    is_prompt: bool,
    line_offset: usize,
    screen: Screen,
    theme: &'a Theme,
    syntax_set: &'a SyntaxSet,
    syntax_ref: &'a SyntaxReference,
}

const TAB_LENGTH: usize = 4;

impl<'a> View<'a> {
    pub fn new(
        theme: &'a Theme,
        syntax_ref: &'a SyntaxReference,
        syntax_set: &'a SyntaxSet,
    ) -> Self {
        let default_style = Style {
            foreground: theme.settings.foreground.unwrap_or(Color::WHITE),
            background: theme.settings.background.unwrap_or(Color::BLACK),
            font_style: FontStyle::empty(),
        };
        View {
            message: None,
            is_prompt: false,
            line_offset: 0,
            screen: Screen::with_default_style(default_style),
            theme,
            syntax_set,
            syntax_ref,
        }
    }

    pub fn message(&mut self, message: &str) {
        self.is_prompt = false;
        self.message = Some(String::from(message));
    }

    pub fn prompt(&mut self, prompt: &str, message: &str) {
        self.is_prompt = true;
        let msg = String::from(prompt) + message;
        self.message = Some(msg);
    }

    pub fn quiet(&mut self) {
        self.is_prompt = false;
        self.message = None;
    }

    pub fn center_view(&mut self, line: usize) {
        self.line_offset = line
            .checked_sub(self.lines_height() as usize / 2)
            .unwrap_or(0);
    }

    pub fn adjust_view(&mut self, line: usize) {
        if line < self.line_offset {
            self.line_offset = line;
        } else if line + 1 >= self.line_offset + self.lines_height() {
            self.line_offset = 1 + line - self.lines_height();
        }
    }

    pub fn scroll_view<T: Editable>(&mut self, offset: isize, content: &T) {
        self.line_offset = cmp::min(
            cmp::max((self.line_offset as isize) + offset, 0),
            (content.line_count() as isize) - 1,
        ) as usize;
    }

    pub fn render<T>(&mut self, content: &T)
    where
        T: Editable + Named + Selectable + Undoable + Modifiable,
    {
        self.screen.clear();
        self.paint_lines(content);
        self.paint_status(content);
        self.paint_message();
        self.paint_cursor(content);
        self.screen.present();
    }

    pub fn translate_coordinates<T>(&self, content: &T, x: u16, y: u16) -> (usize, usize)
    where
        T: Editable,
    {
        let line = cmp::min(
            (y as isize + self.line_offset as isize - 1) as usize,
            content.line_count() - 1,
        );
        let visual_col = (cmp::max(
            0,
            x as isize - self.line_number_width(content.line_count()) as isize - 2,
        )) as usize;
        // find out if we clicked through a tab
        let col = content
            .iter_line(line)
            .scan(0, |state, x| {
                *state += if x == '\t' { TAB_LENGTH } else { 1 };
                Some(*state)
            }).take_while(|&x| x <= visual_col)
            .count();
        (line, col)
    }

    fn paint_message(&self) {
        if let Some(ref message) = self.message {
            let y = self.lines_height() + 1;
            self.screen.draw(0, y, message);
        }
    }

    fn paint_cursor<T>(&mut self, content: &T)
    where
        T: Editable + Selectable,
    {
        // FIXME: don't print the cursor if off screen, though we should in the future for long
        // lines
        if (content.line()) < self.line_offset
            || content.line() >= self.line_offset + self.lines_height()
            || content.col() >= self.lines_width(content.line_count())
            || content.sel().is_some()
        {
            self.screen.hide_cursor();
            return;
        }

        // in the case of a prompt, the cursor should be drawn in the message line
        let (x, y) = if self.is_prompt {
            (
                self.message.clone().unwrap().chars().count(),
                self.lines_height() + 1,
            )
        } else {
            let (a, b) = self.cursor_pos(content);
            (a, b)
        };
        self.screen.move_cursor(x, y);
        self.screen.show_cursor();
    }

    fn paint_status<T>(&self, content: &T)
    where
        T: Editable + Named + Undoable + Modifiable,
    {
        let line = content.line();
        let column = content.col();
        let line_count = content.line_count();
        let advance = ((line + 1) as f64 / line_count as f64 * 100.0).floor();

        let (screen_width, _) = terminal_size().unwrap();
        let empty_line = (0..screen_width).map(|_| ' ').collect::<String>();
        let y = self.lines_height();

        let style = Style {
            background: self.theme.settings.background.unwrap_or(Color::BLACK),
            foreground: self.theme.settings.foreground.unwrap_or(Color::WHITE),
            font_style: FontStyle::empty(),
        };

        self.screen.draw_with_style(0, y, style, &empty_line);
        let mut filename = content.name().clone();
        if content.was_modified() {
            filename.push_str(" *");
        }
        self.screen.draw_with_style(0, y, style, &filename);

        let position_info = format!("{}% {}/{}: {}", advance, line + 1, line_count, column);
        let x = screen_width as usize - position_info.len();
        self.screen.draw_with_style(x, y, style, &position_info);
    }

    fn paint_lines<T>(&mut self, content: &T)
    where
        T: Editable + Selectable,
    {
        let line_offset = self.line_offset as usize;
        let lines_height = self.lines_height() as usize;
        let line_count = content.line_count();

        let line_start = self.line_number_width(line_count) as usize + 1;

        let mut highlighter = HighlightLines::new(self.syntax_ref, self.theme);

        for (i, line) in content.lines().enumerate() {
            let mut line_str = line
                .chars()
                .flat_map(|c| {
                    if c == '\t' {
                        iter::repeat(' ').take(TAB_LENGTH) // FIXME: selection should consider tabs
                    } else {
                        iter::repeat(c).take(1)
                    }
                }).collect::<String>();
            line_str.pop();

            if i < line_offset {
                continue;
            }
            let y = i - line_offset;
            if y >= cmp::min(lines_height, line_count) {
                break;
            }
            let ranges: Vec<(Style, &str)> = highlighter.highlight(&line_str, self.syntax_set);

            // paint line number and initialize display for this line
            let line_index = line_offset + y;
            let line_number_style = Style {
                background: self.theme.settings.gutter.unwrap_or(Color {
                    r: 40,
                    g: 40,
                    b: 40,
                    a: 255,
                }),
                foreground: self.theme.settings.gutter_foreground.unwrap_or(Color {
                    r: 146,
                    g: 131,
                    b: 116,
                    a: 255,
                }),
                font_style: FontStyle::empty(),
            };
            self.screen
                .draw_with_style(0, y, line_number_style, &format!("{}", 1 + line_index));

            self.screen.draw_ranges(line_start, y, ranges);

            // draw selection over
            if let Some((selbeg, selend)) = content.sel() {
                let line_str = String::new() + &line_str + " ";
                let selection_style = Style {
                    foreground: self
                        .theme
                        .settings
                        .selection_foreground
                        .unwrap_or(Color::WHITE),
                    background: self.theme.settings.selection.unwrap_or(Color::BLACK),
                    font_style: FontStyle::empty(),
                };
                let beg = content.line_index_to_char_index(line_index);
                let end = beg + line_str.len() - 1;

                if *selbeg <= beg && *selend >= end {
                    // line is fully inside the selection
                    if line_str.is_empty() {
                        self.screen
                            .draw_with_style(line_start, y, selection_style, " ");
                    } else {
                        self.screen
                            .draw_with_style(line_start, y, selection_style, &line_str);
                    }
                } else if *selbeg >= beg && *selbeg <= end && *selend <= end && *selend >= beg {
                    // selection is inside the line
                    self.screen.draw_with_style(
                        line_start + (*selbeg - beg),
                        y,
                        selection_style,
                        &line_str[(*selbeg - beg)..=(*selend - beg)],
                    );
                } else if *selbeg <= end && *selbeg >= beg {
                    // line contains the beginning of the selection
                    self.screen.draw_with_style(
                        line_start + (*selbeg - beg),
                        y,
                        selection_style,
                        &line_str[(*selbeg - beg)..],
                    );
                } else if *selend <= end && *selend >= beg {
                    // line contains the end of the selection
                    self.screen.draw_with_style(
                        line_start,
                        y,
                        selection_style,
                        &line_str[..=(*selend - beg)],
                    );
                }
            }
        }
    }

    fn cursor_pos<T: Editable>(&self, content: &T) -> (usize, usize) {
        // TODO: column offsetting for long lines
        let line = content.line();
        let first_line = self.line_offset;
        let y = line - first_line as usize;
        // we can't trust the actual column because tabs have variable length
        let visual_col = content.col();
        let column: usize = content
            .iter_line(line)
            .map(|x| if x == '\t' { TAB_LENGTH } else { 1 })
            .take(visual_col)
            .sum();
        (
            (self.line_number_width(content.line_count()) as usize + 1 + column),
            y,
        )
    }

    fn line_number_width(&self, line_count: usize) -> u16 {
        line_count.to_string().len() as u16
    }

    fn status_height(&self) -> u16 {
        2
    }

    pub fn lines_height(&self) -> usize {
        let (_, screen_height) = terminal_size().unwrap();
        let incompressible = self.status_height() as usize;
        cmp::max(screen_height as usize, incompressible) - incompressible
    }

    pub fn lines_width(&self, line_count: usize) -> usize {
        let (screen_width, _) = terminal_size().unwrap();
        let incompressible = self.line_number_width(line_count) as usize + 1;
        cmp::max(screen_width as usize, incompressible) - incompressible
    }
}
<commit_msg>Fix highlighting<commit_after>mod screen;

use self::screen::Screen;
use data::{Editable, Modifiable, Named, Selectable, Undoable};
use std::{cmp, iter};
use syntect::easy::HighlightLines;
use syntect::highlighting::Theme;
use syntect::highlighting::{Color, FontStyle, Style};
use syntect::parsing::{SyntaxReference, SyntaxSet};
use termion::terminal_size;
pub struct View<'a> {
    message: Option<String>,
    is_prompt: bool,
    line_offset: usize,
    screen: Screen,
    theme: &'a Theme,
    syntax_set: &'a SyntaxSet,
    syntax_ref: &'a SyntaxReference,
}

const TAB_LENGTH: usize = 4;

impl<'a> View<'a> {
    pub fn new(
        theme: &'a Theme,
        syntax_ref: &'a SyntaxReference,
        syntax_set: &'a SyntaxSet,
    ) -> Self {
        let default_style = Style {
            foreground: theme.settings.foreground.unwrap_or(Color::WHITE),
            background: theme.settings.background.unwrap_or(Color::BLACK),
            font_style: FontStyle::empty(),
        };
        View {
            message: None,
            is_prompt: false,
            line_offset: 0,
            screen: Screen::with_default_style(default_style),
            theme,
            syntax_set,
            syntax_ref,
        }
    }

    pub fn message(&mut self, message: &str) {
        self.is_prompt = false;
        self.message = Some(String::from(message));
    }

    pub fn prompt(&mut self, prompt: &str, message: &str) {
        self.is_prompt = true;
        let msg = String::from(prompt) + message;
        self.message = Some(msg);
    }

    pub fn quiet(&mut self) {
        self.is_prompt = false;
        self.message = None;
    }

    pub fn center_view(&mut self, line: usize) {
        self.line_offset = line
            .checked_sub(self.lines_height() as usize / 2)
            .unwrap_or(0);
    }

    pub fn adjust_view(&mut self, line: usize) {
        if line < self.line_offset {
            self.line_offset = line;
        } else if line + 1 >= self.line_offset + self.lines_height() {
            self.line_offset = 1 + line - self.lines_height();
        }
    }

    pub fn scroll_view<T: Editable>(&mut self, offset: isize, content: &T) {
        self.line_offset = cmp::min(
            cmp::max((self.line_offset as isize) + offset, 0),
            (content.line_count() as isize) - 1,
        ) as usize;
    }

    pub fn render<T>(&mut self, content: &T)
    where
        T: Editable + Named + Selectable + Undoable + Modifiable,
    {
        self.screen.clear();
        self.paint_lines(content);
        self.paint_status(content);
        self.paint_message();
        self.paint_cursor(content);
        self.screen.present();
    }

    pub fn translate_coordinates<T>(&self, content: &T, x: u16, y: u16) -> (usize, usize)
    where
        T: Editable,
    {
        let line = cmp::min(
            (y as isize + self.line_offset as isize - 1) as usize,
            content.line_count() - 1,
        );
        let visual_col = (cmp::max(
            0,
            x as isize - self.line_number_width(content.line_count()) as isize - 2,
        )) as usize;
        // find out if we clicked through a tab
        let col = content
            .iter_line(line)
            .scan(0, |state, x| {
                *state += if x == '\t' { TAB_LENGTH } else { 1 };
                Some(*state)
            }).take_while(|&x| x <= visual_col)
            .count();
        (line, col)
    }

    fn paint_message(&self) {
        if let Some(ref message) = self.message {
            let y = self.lines_height() + 1;
            self.screen.draw(0, y, message);
        }
    }

    fn paint_cursor<T>(&mut self, content: &T)
    where
        T: Editable + Selectable,
    {
        // FIXME: don't print the cursor if off screen, though we should in the future for long
        // lines
        if (content.line()) < self.line_offset
            || content.line() >= self.line_offset + self.lines_height()
            || content.col() >= self.lines_width(content.line_count())
            || content.sel().is_some()
        {
            self.screen.hide_cursor();
            return;
        }

        // in the case of a prompt, the cursor should be drawn in the message line
        let (x, y) = if self.is_prompt {
            (
                self.message.clone().unwrap().chars().count(),
                self.lines_height() + 1,
            )
        } else {
            let (a, b) = self.cursor_pos(content);
            (a, b)
        };
        self.screen.move_cursor(x, y);
        self.screen.show_cursor();
    }

    fn paint_status<T>(&self, content: &T)
    where
        T: Editable + Named + Undoable + Modifiable,
    {
        let line = content.line();
        let column = content.col();
        let line_count = content.line_count();
        let advance = ((line + 1) as f64 / line_count as f64 * 100.0).floor();

        let (screen_width, _) = terminal_size().unwrap();
        let empty_line = (0..screen_width).map(|_| ' ').collect::<String>();
        let y = self.lines_height();

        let style = Style {
            background: self.theme.settings.background.unwrap_or(Color::BLACK),
            foreground: self.theme.settings.foreground.unwrap_or(Color::WHITE),
            font_style: FontStyle::empty(),
        };

        self.screen.draw_with_style(0, y, style, &empty_line);
        let mut filename = content.name().clone();
        if content.was_modified() {
            filename.push_str(" *");
        }
        self.screen.draw_with_style(0, y, style, &filename);

        let position_info = format!("{}% {}/{}: {}", advance, line + 1, line_count, column);
        let x = screen_width as usize - position_info.len();
        self.screen.draw_with_style(x, y, style, &position_info);
    }

    fn paint_lines<T>(&mut self, content: &T)
    where
        T: Editable + Selectable,
    {
        let line_offset = self.line_offset as usize;
        let lines_height = self.lines_height() as usize;
        let line_count = content.line_count();

        let line_start = self.line_number_width(line_count) as usize + 1;

        let mut highlighter = HighlightLines::new(self.syntax_ref, self.theme);

        for (i, line) in content.lines().enumerate() {
            let mut line_str = line
                .chars()
                .flat_map(|c| {
                    if c == '\t' {
                        iter::repeat(' ').take(TAB_LENGTH) // FIXME: selection should consider tabs
                    } else if c == '\n' {
                        iter::repeat(' ').take(1)
                    } else {
                        iter::repeat(c).take(1)
                    }
                }).collect::<String>();

            let ranges: Vec<(Style, &str)> = highlighter.highlight(&line_str, self.syntax_set);

            if i < line_offset {
                continue;
            }
            let y = i - line_offset;
            if y >= cmp::min(lines_height, line_count) {
                break;
            }

            // paint line number and initialize display for this line
            let line_index = line_offset + y;
            let line_number_style = Style {
                background: self.theme.settings.gutter.unwrap_or(Color {
                    r: 40,
                    g: 40,
                    b: 40,
                    a: 255,
                }),
                foreground: self.theme.settings.gutter_foreground.unwrap_or(Color {
                    r: 146,
                    g: 131,
                    b: 116,
                    a: 255,
                }),
                font_style: FontStyle::empty(),
            };
            self.screen
                .draw_with_style(0, y, line_number_style, &format!("{}", 1 + line_index));

            self.screen.draw_ranges(line_start, y, ranges);

            // draw selection over
            if let Some((selbeg, selend)) = content.sel() {
                let selection_style = Style {
                    foreground: self
                        .theme
                        .settings
                        .selection_foreground
                        .unwrap_or(Color::WHITE),
                    background: self.theme.settings.selection.unwrap_or(Color::BLACK),
                    font_style: FontStyle::empty(),
                };
                let beg = content.line_index_to_char_index(line_index);
                let end = beg + line_str.len() - 1;

                if *selbeg <= beg && *selend >= end {
                    // line is fully inside the selection
                    if line_str.is_empty() {
                        self.screen
                            .draw_with_style(line_start, y, selection_style, " ");
                    } else {
                        self.screen
                            .draw_with_style(line_start, y, selection_style, &line_str);
                    }
                } else if *selbeg >= beg && *selbeg <= end && *selend <= end && *selend >= beg {
                    // selection is inside the line
                    self.screen.draw_with_style(
                        line_start + (*selbeg - beg),
                        y,
                        selection_style,
                        &line_str[(*selbeg - beg)..=(*selend - beg)],
                    );
                } else if *selbeg <= end && *selbeg >= beg {
                    // line contains the beginning of the selection
                    self.screen.draw_with_style(
                        line_start + (*selbeg - beg),
                        y,
                        selection_style,
                        &line_str[(*selbeg - beg)..],
                    );
                } else if *selend <= end && *selend >= beg {
                    // line contains the end of the selection
                    self.screen.draw_with_style(
                        line_start,
                        y,
                        selection_style,
                        &line_str[..=(*selend - beg)],
                    );
                }
            }
        }
    }

    fn cursor_pos<T: Editable>(&self, content: &T) -> (usize, usize) {
        // TODO: column offsetting for long lines
        let line = content.line();
        let first_line = self.line_offset;
        let y = line - first_line as usize;
        // we can't trust the actual column because tabs have variable length
        let visual_col = content.col();
        let column: usize = content
            .iter_line(line)
            .map(|x| if x == '\t' { TAB_LENGTH } else { 1 })
            .take(visual_col)
            .sum();
        (
            (self.line_number_width(content.line_count()) as usize + 1 + column),
            y,
        )
    }

    fn line_number_width(&self, line_count: usize) -> u16 {
        line_count.to_string().len() as u16
    }

    fn status_height(&self) -> u16 {
        2
    }

    pub fn lines_height(&self) -> usize {
        let (_, screen_height) = terminal_size().unwrap();
        let incompressible = self.status_height() as usize;
        cmp::max(screen_height as usize, incompressible) - incompressible
    }

    pub fn lines_width(&self, line_count: usize) -> usize {
        let (screen_width, _) = terminal_size().unwrap();
        let incompressible = self.line_number_width(line_count) as usize + 1;
        cmp::max(screen_width as usize, incompressible) - incompressible
    }
}
<|endoftext|>


<commit_before>//! Generic page struct

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use iron::{IronResult, Set, status};
use iron::response::Response;
use handlebars_iron::Template;

pub struct Page<T: ToJson> {
    title: Option<String>,
    content: T,
    varss: BTreeMap<String, String>,
    varsb: BTreeMap<String, bool>,
    varsi: BTreeMap<String, i64>,
}

impl<T: ToJson> Page<T> {
    pub fn new(content: T) -> Page<T> {
        Page {
            title: None,
            content: content,
            varss: BTreeMap::new(),
            varsb: BTreeMap::new(),
            varsi: BTreeMap::new(),
        }
    }

    /// Sets a string variable
    pub fn set(mut self, var: &str, val: &str) -> Page<T> {
        &self.varss.insert(var.to_owned(), val.to_owned());
        self
    }

    /// Sets a boolean variable
    pub fn set_bool(mut self, var: &str, val: bool) -> Page<T> {
        &self.varsb.insert(var.to_owned(), val);
        self
    }

    /// Sets a boolean variable to true
    pub fn set_true(mut self, var: &str) -> Page<T> {
        &self.varsb.insert(var.to_owned(), true);
        self
    }

    /// Sets an integer variable
    pub fn set_int(mut self, var: &str, val: i64) -> Page<T> {
        &self.varsi.insert(var.to_owned(), val);
        self
    }

    /// Sets title of page
    pub fn title(mut self, title: &str) -> Page<T> {
        self.title = Some(title.to_owned());
        self
    }

    pub fn to_resp(self, template: &str) -> IronResult<Response> {
        let mut resp = Response::new();
        let temp = Template::new(template, self);
        resp.set_mut(temp).set_mut(status::Ok);
        Ok(resp)
    }
}

impl<T: ToJson> ToJson for Page<T> {
    fn to_json(&self) -> Json {
        let mut tree = BTreeMap::new();

        if let Some(ref title) = self.title {
            tree.insert("title".to_owned(), title.to_json());
        }

        tree.insert("content".to_owned(), self.content.to_json());
        tree.insert("cratesfyi_version".to_owned(), ::BUILD_VERSION.to_json());
        tree.insert("varss".to_owned(), self.varss.to_json());
        tree.insert("varsb".to_owned(), self.varsb.to_json());
        tree.insert("varsi".to_owned(), self.varsi.to_json());
        Json::Object(tree)
    }
}
<commit_msg>Add set_status to Page<commit_after>//! Generic page struct

use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use iron::{IronResult, Set, status};
use iron::response::Response;
use handlebars_iron::Template;

pub struct Page<T: ToJson> {
    title: Option<String>,
    content: T,
    status: status::Status,
    varss: BTreeMap<String, String>,
    varsb: BTreeMap<String, bool>,
    varsi: BTreeMap<String, i64>,
}

impl<T: ToJson> Page<T> {
    pub fn new(content: T) -> Page<T> {
        Page {
            title: None,
            content: content,
            status: status::Ok,
            varss: BTreeMap::new(),
            varsb: BTreeMap::new(),
            varsi: BTreeMap::new(),
        }
    }

    /// Sets a string variable
    pub fn set(mut self, var: &str, val: &str) -> Page<T> {
        &self.varss.insert(var.to_owned(), val.to_owned());
        self
    }

    /// Sets a boolean variable
    pub fn set_bool(mut self, var: &str, val: bool) -> Page<T> {
        &self.varsb.insert(var.to_owned(), val);
        self
    }

    /// Sets a boolean variable to true
    pub fn set_true(mut self, var: &str) -> Page<T> {
        &self.varsb.insert(var.to_owned(), true);
        self
    }

    /// Sets an integer variable
    pub fn set_int(mut self, var: &str, val: i64) -> Page<T> {
        &self.varsi.insert(var.to_owned(), val);
        self
    }

    /// Sets title of page
    pub fn title(mut self, title: &str) -> Page<T> {
        self.title = Some(title.to_owned());
        self
    }

    /// Sets status code for response
    pub fn set_status(mut self, s: status::Status) -> Page<T> {
        self.status = s;
        self
    }

    pub fn to_resp(self, template: &str) -> IronResult<Response> {
        let mut resp = Response::new();
        let status = self.status;
        let temp = Template::new(template, self);
        resp.set_mut(temp).set_mut(status);
        Ok(resp)
    }
}

impl<T: ToJson> ToJson for Page<T> {
    fn to_json(&self) -> Json {
        let mut tree = BTreeMap::new();

        if let Some(ref title) = self.title {
            tree.insert("title".to_owned(), title.to_json());
        }

        tree.insert("content".to_owned(), self.content.to_json());
        tree.insert("cratesfyi_version".to_owned(), ::BUILD_VERSION.to_json());
        tree.insert("varss".to_owned(), self.varss.to_json());
        tree.insert("varsb".to_owned(), self.varsb.to_json());
        tree.insert("varsi".to_owned(), self.varsi.to_json());
        Json::Object(tree)
    }
}
<|endoftext|>