<commit_before>// This is a part of rust-encoding.
// Copyright (c) 2013-2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

/*!

# Rust-encoding

Character encoding support for Rust.
It is based on [WHATWG Encoding Standard](http://encoding.spec.whatwg.org/),
and also provides an advanced interface for error detection and recovery.

## Simple Usage

To encode a string:

~~~~ {.rust}
use encoding::{Encoding, EncodeStrict};
use encoding::all::ISO_8859_1;

assert_eq!(ISO_8859_1.encode("caf\xe9", EncodeStrict),
           Ok(vec!(99,97,102,233)));
~~~~

To encode a string with unrepresentable characters:

~~~~ {.rust}
use encoding::{Encoding, EncodeStrict, EncodeReplace, EncodeIgnore, EncodeNcrEscape};
use encoding::all::ISO_8859_2;

assert!(ISO_8859_2.encode("Acme\xa9", EncodeStrict).is_err());
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeReplace),
           Ok(vec!(65,99,109,101,63)));
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeIgnore),
           Ok(vec!(65,99,109,101)));
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeNcrEscape),
           Ok(vec!(65,99,109,101,38,35,49,54,57,59)));
~~~~

To decode a byte sequence:

~~~~ {.rust}
use encoding::{Encoding, DecodeStrict};
use encoding::all::ISO_8859_1;

assert_eq!(ISO_8859_1.decode([99,97,102,233], DecodeStrict),
           Ok("caf\xe9".to_string()));
~~~~

To decode a byte sequence with invalid sequences:

~~~~ {.rust}
use encoding::{Encoding, DecodeStrict, DecodeReplace, DecodeIgnore};
use encoding::all::ISO_8859_6;

assert!(ISO_8859_6.decode([65,99,109,101,169], DecodeStrict).is_err());
assert_eq!(ISO_8859_6.decode([65,99,109,101,169], DecodeReplace),
           Ok("Acme\ufffd".to_string()));
assert_eq!(ISO_8859_6.decode([65,99,109,101,169], DecodeIgnore),
           Ok("Acme".to_string()));
~~~~

A practical example of custom encoder traps:

~~~~ {.rust}
use encoding::{Encoding, Encoder, ByteWriter, EncoderTrap, EncoderCall, DecodeStrict};
use encoding::all::ASCII;

// hexadecimal numeric character reference replacement
fn hex_ncr_escape(_encoder: &mut Encoder, input: &str, output: &mut ByteWriter) -> bool {
    let escapes: Vec<String> =
        input.chars().map(|ch| format!("&#x{:x};", ch as int)).collect();
    let escapes = escapes.concat();
    output.write_bytes(escapes.as_bytes());
    true
}
#[allow(non_uppercase_statics)] static HexNcrEscape: EncoderTrap = EncoderCall(hex_ncr_escape);

let orig = "Hello, 世界!".to_string();
let encoded = ASCII.encode(orig.as_slice(), HexNcrEscape).unwrap();
assert_eq!(ASCII.decode(encoded.as_slice(), DecodeStrict),
           Ok("Hello, 世界!".to_string()));
~~~~

Getting the encoding from the string label, as specified in WHATWG Encoding standard:

~~~~ {.rust}
use encoding::{Encoding, DecodeReplace};
use encoding::label::encoding_from_whatwg_label;
use encoding::all::WINDOWS_949;

let euckr = encoding_from_whatwg_label("euc-kr").unwrap();
assert_eq!(euckr.name(), "windows-949");
assert_eq!(euckr.whatwg_name(), Some("euc-kr")); // for the sake of compatibility
let broken = &[0xbf, 0xec, 0xbf, 0xcd, 0xff, 0xbe, 0xd3];
assert_eq!(euckr.decode(broken, DecodeReplace),
           Ok("\uc6b0\uc640\ufffd\uc559".to_string()));

// corresponding rust-encoding native API:
assert_eq!(WINDOWS_949.decode(broken, DecodeReplace),
           Ok("\uc6b0\uc640\ufffd\uc559".to_string()));
~~~~

## Detailed Usage

There are three main entry points to rust-encoding.

**`Encoding`** is a single character encoding.
It contains `encode` and `decode` methods for converting `String` to `Vec<u8>` and vice versa.
For the error handling, they receive **traps** (`EncoderCall` and `DecoderCall` respectively)
which replace any error with some string (e.g. `U+FFFD`) or sequence (e.g. `?`).
You can also use `EncodeStrict` and `DecodeStrict` traps to stop on an error.

There are two ways to get `Encoding`:

* `encoding::all` has static items for every supported encoding.
  You should use them when the encoding would not change or only handful of them are required.
  Combined with link-time optimization, any unused encoding would be discarded from the binary.
* `encoding::label` has functions to dynamically get an encoding from given string ("label").
  They will return a static reference to the encoding, which type is also known as `EncodingRef`.
  It is useful when a list of required encodings is not available in advance,
  but it will result in the larger binary and missed optimization opportunities.

**`Encoder`** is an experimental incremental encoder.
At each step of `raw_feed`, it receives a slice of string
and emits any encoded bytes to a generic `ByteWriter` (normally `Vec<u8>`).
It will stop at the first error if any, and would return a `CodecError` struct in that case.
The caller is responsible for calling `raw_finish` at the end of encoding process.

**`Decoder`** is an experimental incremental decoder.
At each step of `raw_feed`, it receives a slice of byte sequence
and emits any decoded characters to a generic `StringWriter` (normally `String`).
Otherwise it is identical to `Encoder`s.

One should prefer `Encoding::{encode,decode}` as a primary interface.
`Encoder` and `Decoder` is experimental and can change substantially.
See the additional documents on `encoding::types` module for more information on them.

## Supported Encodings

Rust-encoding covers all encodings specified by WHATWG Encoding Standard and some more:

* 7-bit strict ASCII (`ascii`)
* UTF-8 (`utf-8`)
* UTF-16 in little endian (`utf-16` or `utf-16le`) and big endian (`utf-16be`)
* All single byte encoding in WHATWG Encoding Standard:
    * IBM code page 866
    * ISO 8859-{2,3,4,5,6,7,8,10,13,14,15,16}
    * KOI8-R, KOI8-U
    * MacRoman (`macintosh`), Macintosh Cyrillic encoding (`x-mac-cyrillic`)
    * Windows code pages 874, 1250, 1251, 1252 (instead of ISO 8859-1), 1253,
      1254 (instead of ISO 8859-9), 1255, 1256, 1257, 1258
* All multi byte encodings in WHATWG Encoding Standard:
    * Windows code page 949 (`euc-kr`, since the strict EUC-KR is hardly used)
    * EUC-JP and Windows code page 932 (`shift_jis`,
      since it's the most widespread extension to Shift_JIS)
    * ISO-2022-JP with asymmetric JIS X 0212 support
    * GB 18030
    * HZ
    * Big5-2003 with HKSCS-2008 extensions
* ISO 8859-1 (distinct from Windows code page 1252)

Parenthesized names refer to the encoding's primary name assigned by WHATWG Encoding Standard.

Many legacy character encodings lack the proper specification,
and even those that have a specification are highly dependent of the actual implementation.
Consequently one should be careful when picking a desired character encoding.
The only standards reliable in this regard are WHATWG Encoding Standard and
[vendor-provided mappings from the Unicode consortium](http://www.unicode.org/Public/MAPPINGS/).
Whenever in doubt, look at the source code and specifications for detailed explanations.

*/

#![crate_name = "encoding"]
#![crate_type = "lib"]
#![comment = "Character encoding support for Rust"]
#![license = "MIT"]

#![feature(globs, macro_rules, slicing_syntax)]

#![allow(experimental)]

#[cfg(test)] extern crate test;

pub use self::types::{CodecError, ByteWriter, StringWriter,
                      Encoder, Decoder, EncodingRef, Encoding,
                      EncoderTrapFunc, DecoderTrapFunc, DecoderTrap,
                      DecodeStrict, DecodeReplace, DecodeIgnore,
                      EncoderTrap, EncodeStrict, EncodeReplace,
                      EncodeIgnore, EncodeNcrEscape, decode,
                      EncoderCall, DecoderCall}; // reexport

mod util;
#[cfg(test)] mod testutils;

pub mod types;

/// Indices used for character encoding implementation. Semi-internal.
#[unstable]
pub mod index {
    pub mod ibm866;
    pub mod iso_8859_2;
    pub mod iso_8859_3;
    pub mod iso_8859_4;
    pub mod iso_8859_5;
    pub mod iso_8859_6;
    pub mod iso_8859_7;
    pub mod iso_8859_8;
    pub mod iso_8859_10;
    pub mod iso_8859_13;
    pub mod iso_8859_14;
    pub mod iso_8859_15;
    pub mod iso_8859_16;
    pub mod koi8_r;
    pub mod koi8_u;
    pub mod macintosh;
    pub mod windows_874;
    pub mod windows_1250;
    pub mod windows_1251;
    pub mod windows_1252;
    pub mod windows_1253;
    pub mod windows_1254;
    pub mod windows_1255;
    pub mod windows_1256;
    pub mod windows_1257;
    pub mod windows_1258;
    pub mod x_mac_cyrillic;
    pub mod big5;
    pub mod euc_kr;
    pub mod gb18030;
    pub mod gb18030_ranges;
    pub mod jis0208;
    pub mod jis0212;
}

/// Codec implementations.
#[unstable]
pub mod codec {
    pub mod error;
    pub mod ascii;
    pub mod singlebyte;
    pub mod utf_8;
    pub mod utf_16;
    pub mod korean;
    pub mod japanese;
    pub mod simpchinese;
    pub mod tradchinese;
    pub mod whatwg;
}

pub mod all;
pub mod label;

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

    #[test]
    fn test_decode() {
        fn test_one(input: &[u8], expected_result: &str, expected_encoding: &str) {
            let (result, used_encoding) = decode(
                input, DecodeStrict, all::ISO_8859_1 as EncodingRef);
            let result = result.unwrap();
            assert_eq!(used_encoding.name(), expected_encoding);
            assert_eq!(result[], expected_result);
        }

        test_one([0xEF, 0xBB, 0xBF, 0xC3, 0xA9], "é", "utf-8");
        test_one([0xC3, 0xA9], "Ã©", "iso-8859-1");

        test_one([0xFE, 0xFF, 0x00, 0xE9], "é", "utf-16be");
        test_one([0x00, 0xE9], "\x00é", "iso-8859-1");

        test_one([0xFF, 0xFE, 0xE9, 0x00], "é", "utf-16le");
        test_one([0xE9, 0x00], "é\x00", "iso-8859-1");
    }
}

<commit_msg>temporary measure against the travis failure...<commit_after>// This is a part of rust-encoding.
// Copyright (c) 2013-2014, Kang Seonghoon.
// See README.md and LICENSE.txt for details.

/*!

# Rust-encoding

Character encoding support for Rust.
It is based on [WHATWG Encoding Standard](http://encoding.spec.whatwg.org/),
and also provides an advanced interface for error detection and recovery.

## Simple Usage

To encode a string:

~~~~ {.rust}
use encoding::{Encoding, EncodeStrict};
use encoding::all::ISO_8859_1;

assert_eq!(ISO_8859_1.encode("caf\xe9", EncodeStrict),
           Ok(vec!(99,97,102,233)));
~~~~

To encode a string with unrepresentable characters:

~~~~ {.rust}
use encoding::{Encoding, EncodeStrict, EncodeReplace, EncodeIgnore, EncodeNcrEscape};
use encoding::all::ISO_8859_2;

assert!(ISO_8859_2.encode("Acme\xa9", EncodeStrict).is_err());
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeReplace),
           Ok(vec!(65,99,109,101,63)));
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeIgnore),
           Ok(vec!(65,99,109,101)));
assert_eq!(ISO_8859_2.encode("Acme\xa9", EncodeNcrEscape),
           Ok(vec!(65,99,109,101,38,35,49,54,57,59)));
~~~~

To decode a byte sequence:

~~~~ {.rust}
use encoding::{Encoding, DecodeStrict};
use encoding::all::ISO_8859_1;

assert_eq!(ISO_8859_1.decode([99,97,102,233], DecodeStrict),
           Ok("caf\xe9".to_string()));
~~~~

To decode a byte sequence with invalid sequences:

~~~~ {.rust}
use encoding::{Encoding, DecodeStrict, DecodeReplace, DecodeIgnore};
use encoding::all::ISO_8859_6;

assert!(ISO_8859_6.decode([65,99,109,101,169], DecodeStrict).is_err());
assert_eq!(ISO_8859_6.decode([65,99,109,101,169], DecodeReplace),
           Ok("Acme\ufffd".to_string()));
assert_eq!(ISO_8859_6.decode([65,99,109,101,169], DecodeIgnore),
           Ok("Acme".to_string()));
~~~~

A practical example of custom encoder traps:

~~~~ {.rust}
use encoding::{Encoding, Encoder, ByteWriter, EncoderTrap, EncoderCall, DecodeStrict};
use encoding::all::ASCII;

// hexadecimal numeric character reference replacement
fn hex_ncr_escape(_encoder: &mut Encoder, input: &str, output: &mut ByteWriter) -> bool {
    let escapes: Vec<String> =
        input.chars().map(|ch| format!("&#x{:x};", ch as int)).collect();
    let escapes = escapes.concat();
    output.write_bytes(escapes.as_bytes());
    true
}
#[allow(non_uppercase_statics)] static HexNcrEscape: EncoderTrap = EncoderCall(hex_ncr_escape);

let orig = "Hello, 世界!".to_string();
let encoded = ASCII.encode(orig.as_slice(), HexNcrEscape).unwrap();
assert_eq!(ASCII.decode(encoded.as_slice(), DecodeStrict),
           Ok("Hello, 世界!".to_string()));
~~~~

Getting the encoding from the string label, as specified in WHATWG Encoding standard:

~~~~ {.rust}
use encoding::{Encoding, DecodeReplace};
use encoding::label::encoding_from_whatwg_label;
use encoding::all::WINDOWS_949;

let euckr = encoding_from_whatwg_label("euc-kr").unwrap();
assert_eq!(euckr.name(), "windows-949");
assert_eq!(euckr.whatwg_name(), Some("euc-kr")); // for the sake of compatibility
let broken = &[0xbf, 0xec, 0xbf, 0xcd, 0xff, 0xbe, 0xd3];
assert_eq!(euckr.decode(broken, DecodeReplace),
           Ok("\uc6b0\uc640\ufffd\uc559".to_string()));

// corresponding rust-encoding native API:
assert_eq!(WINDOWS_949.decode(broken, DecodeReplace),
           Ok("\uc6b0\uc640\ufffd\uc559".to_string()));
~~~~

## Detailed Usage

There are three main entry points to rust-encoding.

**`Encoding`** is a single character encoding.
It contains `encode` and `decode` methods for converting `String` to `Vec<u8>` and vice versa.
For the error handling, they receive **traps** (`EncoderCall` and `DecoderCall` respectively)
which replace any error with some string (e.g. `U+FFFD`) or sequence (e.g. `?`).
You can also use `EncodeStrict` and `DecodeStrict` traps to stop on an error.

There are two ways to get `Encoding`:

* `encoding::all` has static items for every supported encoding.
  You should use them when the encoding would not change or only handful of them are required.
  Combined with link-time optimization, any unused encoding would be discarded from the binary.
* `encoding::label` has functions to dynamically get an encoding from given string ("label").
  They will return a static reference to the encoding, which type is also known as `EncodingRef`.
  It is useful when a list of required encodings is not available in advance,
  but it will result in the larger binary and missed optimization opportunities.

**`Encoder`** is an experimental incremental encoder.
At each step of `raw_feed`, it receives a slice of string
and emits any encoded bytes to a generic `ByteWriter` (normally `Vec<u8>`).
It will stop at the first error if any, and would return a `CodecError` struct in that case.
The caller is responsible for calling `raw_finish` at the end of encoding process.

**`Decoder`** is an experimental incremental decoder.
At each step of `raw_feed`, it receives a slice of byte sequence
and emits any decoded characters to a generic `StringWriter` (normally `String`).
Otherwise it is identical to `Encoder`s.

One should prefer `Encoding::{encode,decode}` as a primary interface.
`Encoder` and `Decoder` is experimental and can change substantially.
See the additional documents on `encoding::types` module for more information on them.

## Supported Encodings

Rust-encoding covers all encodings specified by WHATWG Encoding Standard and some more:

* 7-bit strict ASCII (`ascii`)
* UTF-8 (`utf-8`)
* UTF-16 in little endian (`utf-16` or `utf-16le`) and big endian (`utf-16be`)
* All single byte encoding in WHATWG Encoding Standard:
    * IBM code page 866
    * ISO 8859-{2,3,4,5,6,7,8,10,13,14,15,16}
    * KOI8-R, KOI8-U
    * MacRoman (`macintosh`), Macintosh Cyrillic encoding (`x-mac-cyrillic`)
    * Windows code pages 874, 1250, 1251, 1252 (instead of ISO 8859-1), 1253,
      1254 (instead of ISO 8859-9), 1255, 1256, 1257, 1258
* All multi byte encodings in WHATWG Encoding Standard:
    * Windows code page 949 (`euc-kr`, since the strict EUC-KR is hardly used)
    * EUC-JP and Windows code page 932 (`shift_jis`,
      since it's the most widespread extension to Shift_JIS)
    * ISO-2022-JP with asymmetric JIS X 0212 support
    * GB 18030
    * HZ
    * Big5-2003 with HKSCS-2008 extensions
* ISO 8859-1 (distinct from Windows code page 1252)

Parenthesized names refer to the encoding's primary name assigned by WHATWG Encoding Standard.

Many legacy character encodings lack the proper specification,
and even those that have a specification are highly dependent of the actual implementation.
Consequently one should be careful when picking a desired character encoding.
The only standards reliable in this regard are WHATWG Encoding Standard and
[vendor-provided mappings from the Unicode consortium](http://www.unicode.org/Public/MAPPINGS/).
Whenever in doubt, look at the source code and specifications for detailed explanations.

*/

#![crate_name = "encoding"]
#![crate_type = "lib"]
#![comment = "Character encoding support for Rust"]
#![license = "MIT"]

#![allow(unknown_features)] // temporary measure for rust-nightly 2014-10-04
#![feature(globs, macro_rules, slicing_syntax)]

#![allow(experimental)]

#[cfg(test)] extern crate test;

pub use self::types::{CodecError, ByteWriter, StringWriter,
                      Encoder, Decoder, EncodingRef, Encoding,
                      EncoderTrapFunc, DecoderTrapFunc, DecoderTrap,
                      DecodeStrict, DecodeReplace, DecodeIgnore,
                      EncoderTrap, EncodeStrict, EncodeReplace,
                      EncodeIgnore, EncodeNcrEscape, decode,
                      EncoderCall, DecoderCall}; // reexport

mod util;
#[cfg(test)] mod testutils;

pub mod types;

/// Indices used for character encoding implementation. Semi-internal.
#[unstable]
pub mod index {
    pub mod ibm866;
    pub mod iso_8859_2;
    pub mod iso_8859_3;
    pub mod iso_8859_4;
    pub mod iso_8859_5;
    pub mod iso_8859_6;
    pub mod iso_8859_7;
    pub mod iso_8859_8;
    pub mod iso_8859_10;
    pub mod iso_8859_13;
    pub mod iso_8859_14;
    pub mod iso_8859_15;
    pub mod iso_8859_16;
    pub mod koi8_r;
    pub mod koi8_u;
    pub mod macintosh;
    pub mod windows_874;
    pub mod windows_1250;
    pub mod windows_1251;
    pub mod windows_1252;
    pub mod windows_1253;
    pub mod windows_1254;
    pub mod windows_1255;
    pub mod windows_1256;
    pub mod windows_1257;
    pub mod windows_1258;
    pub mod x_mac_cyrillic;
    pub mod big5;
    pub mod euc_kr;
    pub mod gb18030;
    pub mod gb18030_ranges;
    pub mod jis0208;
    pub mod jis0212;
}

/// Codec implementations.
#[unstable]
pub mod codec {
    pub mod error;
    pub mod ascii;
    pub mod singlebyte;
    pub mod utf_8;
    pub mod utf_16;
    pub mod korean;
    pub mod japanese;
    pub mod simpchinese;
    pub mod tradchinese;
    pub mod whatwg;
}

pub mod all;
pub mod label;

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

    #[test]
    fn test_decode() {
        fn test_one(input: &[u8], expected_result: &str, expected_encoding: &str) {
            let (result, used_encoding) = decode(
                input, DecodeStrict, all::ISO_8859_1 as EncodingRef);
            let result = result.unwrap();
            assert_eq!(used_encoding.name(), expected_encoding);
            assert_eq!(result[], expected_result);
        }

        test_one([0xEF, 0xBB, 0xBF, 0xC3, 0xA9], "é", "utf-8");
        test_one([0xC3, 0xA9], "Ã©", "iso-8859-1");

        test_one([0xFE, 0xFF, 0x00, 0xE9], "é", "utf-16be");
        test_one([0x00, 0xE9], "\x00é", "iso-8859-1");

        test_one([0xFF, 0xFE, 0xE9, 0x00], "é", "utf-16le");
        test_one([0xE9, 0x00], "é\x00", "iso-8859-1");
    }
}

<|endoftext|>


<commit_before>use super::ast_context::AstContext;
use super::graph_utils;
use super::{AstNode, CondContext, Condition, NodeSet};

use petgraph::algo;
use petgraph::prelude::*;
use petgraph::visit::{IntoNodeReferences, Topo};

use std::collections::HashMap;

pub(super) struct Refiner<'cd, A: AstContext> {
    pub cctx: CondContext<'cd, A>,
}
impl<'cd, A: AstContext> Copy for Refiner<'cd, A> {}
impl<'cd, A: AstContext> Clone for Refiner<'cd, A> {
    fn clone(&self) -> Self {
        *self
    }
}

type RefinementAstNode<'cd, A> = (Condition<'cd, A>, AstNode<'cd, A>);

impl<'cd, A: AstContext> Refiner<'cd, A> {
    pub(super) fn refine_ast_seq(
        self,
        mut graph: StableDiGraph<RefinementAstNode<'cd, A>, ()>,
    ) -> AstNode<'cd, A> {
        // look for pairs of nodes whose reaching conditions are opposites
        loop {
            let mut if_else_cond = None;
            'l: for (_, &(ca, _)) in graph.node_references() {
                for (_, &(cb, _)) in graph.node_references() {
                    let not_cb = self.cctx.mk_not(cb);
                    if ca == not_cb {
                        if_else_cond = Some((ca, cb));
                        break 'l;
                    }
                }
            }

            if let Some((cond, not_cond)) = if_else_cond {
                let _changed = self.try_group_by_cond(cond, not_cond, &mut graph);
                debug_assert!(_changed);
            } else {
                break;
            }
        }

        // iterate through every node in topological order and try to group by
        // that condition
        'm: loop {
            let mut topo = Topo::new(&graph);
            loop {
                if let Some(n) = topo.next(&graph) {
                    let cond = graph[n].0;
                    let changed = self.try_group_by_cond(cond, self.cctx.mk_not(cond), &mut graph);
                    if changed {
                        // restart traversal
                        break;
                    }
                } else {
                    // no more groupings
                    break 'm;
                }
            }
        }

        let mut ast_seq = Vec::new();

        // remove all nodes in topological order
        let mut topo = Topo::new(&graph);
        while let Some(node) = topo.next(&graph) {
            let (cond, ast) = graph.remove_node(node).unwrap();
            ast_seq.push(mk_cond(cond, Box::new(ast), None));
        }

        if ast_seq.len() == 1 {
            ast_seq.pop().unwrap()
        } else {
            AstNode::Seq(ast_seq)
        }
    }

    fn try_group_by_cond(
        self,
        cond: Condition<'cd, A>,
        not_cond: Condition<'cd, A>,
        graph: &mut StableDiGraph<RefinementAstNode<'cd, A>, ()>,
    ) -> bool {
        if cond.is_true() {
            return false;
        }
        let mut then_cands = HashMap::new();
        let mut else_cands = HashMap::new();
        let mut rest = Vec::with_capacity(graph.node_count());
        for node in graph.node_indices() {
            let orig_cond = graph[node].0;
            if let Some(new_cond) = self.cctx.remove_and(cond, orig_cond) {
                then_cands.insert(node, new_cond);
            } else if let Some(new_cond) = self.cctx.remove_and(not_cond, orig_cond) {
                else_cands.insert(node, new_cond);
            } else {
                rest.push(node);
            }
        }

        if then_cands.len() + else_cands.len() >= 2 {
            if then_cands.is_empty() {
                graph_utils::contract_nodes_and_map(
                    graph,
                    else_cands.keys().collect(),
                    |node, (_, ast)| (else_cands[&node], ast),
                    |_, _| (),
                    |else_graph| (not_cond, self.refine_ast_seq(else_graph)),
                );
            } else {
                let then_node = graph_utils::contract_nodes_and_map(
                    graph,
                    then_cands.keys().collect(),
                    |node, (_, ast)| (then_cands[&node], ast),
                    |_, _| (),
                    |then_graph| (cond, self.refine_ast_seq(then_graph)),
                );
                if !else_cands.is_empty() {
                    let else_node = graph_utils::contract_nodes_and_map(
                        graph,
                        else_cands.keys().collect(),
                        |node, (_, ast)| (else_cands[&node], ast),
                        |_, _| (),
                        |else_graph| (not_cond, self.refine_ast_seq(else_graph)),
                    );

                    debug_assert!(graph.find_edge_undirected(then_node, else_node).is_none());
                    let preds: NodeSet = graph
                        .neighbors_directed(then_node, Incoming)
                        .chain(graph.neighbors_directed(else_node, Incoming))
                        .collect();
                    let succs: NodeSet = graph
                        .neighbors_directed(then_node, Outgoing)
                        .chain(graph.neighbors_directed(else_node, Outgoing))
                        .collect();

                    let (_, then_ast) = graph.remove_node(then_node).unwrap();
                    let (_, else_ast) = graph.remove_node(else_node).unwrap();
                    let if_node = graph.add_node((
                        self.cctx.mk_true(),
                        AstNode::Cond(cond, Box::new(then_ast), Some(Box::new(else_ast))),
                    ));

                    for p in &preds {
                        graph.add_edge(p, if_node, ());
                    }
                    for s in &succs {
                        graph.add_edge(if_node, s, ());
                    }
                }
            }
            debug_assert!(!algo::is_cyclic_directed(&*graph));
            true
        } else {
            false
        }
    }
}

fn mk_cond<'cd, A: AstContext>(
    cond: Condition<'cd, A>,
    then_node: Box<AstNode<'cd, A>>,
    else_node_opt: Option<Box<AstNode<'cd, A>>>,
) -> AstNode<'cd, A> {
    if cond.is_true() {
        *then_node
    } else {
        AstNode::Cond(cond, then_node, else_node_opt)
    }
}
<commit_msg>[ctrl_flow_struct] Implement some trivial simplifications<commit_after>use super::ast_context::AstContext;
use super::graph_utils;
use super::{AstNode, CondContext, Condition, NodeSet};

use petgraph::algo;
use petgraph::prelude::*;
use petgraph::visit::{IntoNodeReferences, Topo};

use std::collections::HashMap;

pub(super) struct Refiner<'cd, A: AstContext> {
    pub cctx: CondContext<'cd, A>,
}
impl<'cd, A: AstContext> Copy for Refiner<'cd, A> {}
impl<'cd, A: AstContext> Clone for Refiner<'cd, A> {
    fn clone(&self) -> Self {
        *self
    }
}

type RefinementAstNode<'cd, A> = (Condition<'cd, A>, AstNode<'cd, A>);

impl<'cd, A: AstContext> Refiner<'cd, A> {
    pub(super) fn refine_ast_seq(
        self,
        mut graph: StableDiGraph<RefinementAstNode<'cd, A>, ()>,
    ) -> AstNode<'cd, A> {
        // look for pairs of nodes whose reaching conditions are opposites
        loop {
            let mut if_else_cond = None;
            'l: for (_, &(ca, _)) in graph.node_references() {
                for (_, &(cb, _)) in graph.node_references() {
                    let not_cb = self.cctx.mk_not(cb);
                    if ca == not_cb {
                        if_else_cond = Some((ca, cb));
                        break 'l;
                    }
                }
            }

            if let Some((cond, not_cond)) = if_else_cond {
                let _changed = self.try_group_by_cond(cond, not_cond, &mut graph);
                debug_assert!(_changed);
            } else {
                break;
            }
        }

        // iterate through every node in topological order and try to group by
        // that condition
        'm: loop {
            let mut topo = Topo::new(&graph);
            loop {
                if let Some(n) = topo.next(&graph) {
                    let cond = graph[n].0;
                    let changed = self.try_group_by_cond(cond, self.cctx.mk_not(cond), &mut graph);
                    if changed {
                        // restart traversal
                        break;
                    }
                } else {
                    // no more groupings
                    break 'm;
                }
            }
        }

        let mut ast_seq = Vec::new();

        // remove all nodes in topological order
        let mut topo = Topo::new(&graph);
        while let Some(node) = topo.next(&graph) {
            let (cond, ast) = graph.remove_node(node).unwrap();
            ast_seq.push(mk_cond(cond, Box::new(ast), None));
        }

        self.simplify_ast_node(AstNode::Seq(ast_seq))
            .unwrap_or_default()
    }

    fn try_group_by_cond(
        self,
        cond: Condition<'cd, A>,
        not_cond: Condition<'cd, A>,
        graph: &mut StableDiGraph<RefinementAstNode<'cd, A>, ()>,
    ) -> bool {
        if cond.is_true() {
            return false;
        }
        let mut then_cands = HashMap::new();
        let mut else_cands = HashMap::new();
        let mut rest = Vec::with_capacity(graph.node_count());
        for node in graph.node_indices() {
            let orig_cond = graph[node].0;
            if let Some(new_cond) = self.cctx.remove_and(cond, orig_cond) {
                then_cands.insert(node, new_cond);
            } else if let Some(new_cond) = self.cctx.remove_and(not_cond, orig_cond) {
                else_cands.insert(node, new_cond);
            } else {
                rest.push(node);
            }
        }

        if then_cands.len() + else_cands.len() >= 2 {
            if then_cands.is_empty() {
                graph_utils::contract_nodes_and_map(
                    graph,
                    else_cands.keys().collect(),
                    |node, (_, ast)| (else_cands[&node], ast),
                    |_, _| (),
                    |else_graph| (not_cond, self.refine_ast_seq(else_graph)),
                );
            } else {
                let then_node = graph_utils::contract_nodes_and_map(
                    graph,
                    then_cands.keys().collect(),
                    |node, (_, ast)| (then_cands[&node], ast),
                    |_, _| (),
                    |then_graph| (cond, self.refine_ast_seq(then_graph)),
                );
                if !else_cands.is_empty() {
                    let else_node = graph_utils::contract_nodes_and_map(
                        graph,
                        else_cands.keys().collect(),
                        |node, (_, ast)| (else_cands[&node], ast),
                        |_, _| (),
                        |else_graph| (not_cond, self.refine_ast_seq(else_graph)),
                    );

                    debug_assert!(graph.find_edge_undirected(then_node, else_node).is_none());
                    let preds: NodeSet = graph
                        .neighbors_directed(then_node, Incoming)
                        .chain(graph.neighbors_directed(else_node, Incoming))
                        .collect();
                    let succs: NodeSet = graph
                        .neighbors_directed(then_node, Outgoing)
                        .chain(graph.neighbors_directed(else_node, Outgoing))
                        .collect();

                    let (_, then_ast) = graph.remove_node(then_node).unwrap();
                    let (_, else_ast) = graph.remove_node(else_node).unwrap();
                    let if_node = graph.add_node((
                        self.cctx.mk_true(),
                        AstNode::Cond(cond, Box::new(then_ast), Some(Box::new(else_ast))),
                    ));

                    for p in &preds {
                        graph.add_edge(p, if_node, ());
                    }
                    for s in &succs {
                        graph.add_edge(if_node, s, ());
                    }
                }
            }
            debug_assert!(!algo::is_cyclic_directed(&*graph));
            true
        } else {
            false
        }
    }

    /// Performs trivial simplifications.
    fn simplify_ast_node(self, ast: AstNode<'cd, A>) -> Option<AstNode<'cd, A>> {
        use super::AstNode::*;
        match ast {
            BasicBlock(b) => Some(BasicBlock(b)),
            Seq(seq) => {
                let mut new_seq: Vec<_> = seq
                    .into_iter()
                    .flat_map(|a| {
                        if let Some(a) = self.simplify_ast_node(a) {
                            if let Seq(s) = a {
                                s
                            } else {
                                vec![a]
                            }
                        } else {
                            Vec::new()
                        }
                    })
                    .collect();
                match new_seq.len() {
                    0 => None,
                    1 => Some(new_seq.pop().unwrap()),
                    _ => Some(Seq(new_seq)),
                }
            }
            Cond(c, t, oe) => {
                let ot = self.simplify_ast_node(*t);
                let oe = oe.and_then(|e| self.simplify_ast_node(*e));
                if c.is_true() {
                    ot
                } else if c.is_false() {
                    oe
                } else {
                    if let Some(t) = ot {
                        Some(Cond(c, Box::new(t), oe.map(Box::new)))
                    } else {
                        if let Some(e) = oe {
                            Some(Cond(self.cctx.mk_not(c), Box::new(e), None))
                        } else {
                            None
                        }
                    }
                }
            }
            Loop(t, b) => {
                let b = self.simplify_ast_node(*b).unwrap_or_default();
                Some(Loop(t, Box::new(b)))
            }
            Switch(v, cases, default) => {
                let cases: Vec<_> = cases
                    .into_iter()
                    .filter_map(|(vs, a)| self.simplify_ast_node(a).map(|a| (vs, a)))
                    .collect();
                let default = self.simplify_ast_node(*default);
                if cases.is_empty() {
                    default
                } else {
                    Some(Switch(v, cases, Box::new(default.unwrap_or_default())))
                }
            }
        }
    }
}

fn mk_cond<'cd, A: AstContext>(
    cond: Condition<'cd, A>,
    then_node: Box<AstNode<'cd, A>>,
    else_node_opt: Option<Box<AstNode<'cd, A>>>,
) -> AstNode<'cd, A> {
    if cond.is_true() {
        *then_node
    } else {
        AstNode::Cond(cond, then_node, else_node_opt)
    }
}
<|endoftext|>


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

use ast::{Function, Expr, Statement};
use rich_number::RichNumber;
use prelude::setup_prelude;

const LOWEST_PRECEDENCE: u8 = 0;
const HIGHEST_PRECEDENCE: u8 = 9;
const FUNCTION_PRECEDENCE: u8 = HIGHEST_PRECEDENCE;

#[derive(PartialEq, Debug)]
pub enum EvalError {
    UnknownSymbol(String),
}

pub type EvalResult = Result<ContextItem, EvalError>;

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

#[derive(PartialEq, Debug, Clone)]
pub enum ContextItem {
    Number(RichNumber),
    Definition {
        // number from 0 to 9 where 9 is the highest precedence
        precedence: u8,
        fixity: Fixity,
        function: Function,
    },
    BuiltInMethod(fn(Vec<ContextItem>) -> EvalResult),
    Constant(String),
    Boolean(bool),
    Nothing,
}

impl ContextItem {
    pub fn unwrap_number(self) -> RichNumber {
        match self {
            ContextItem::Number(num) => num,
            _ => panic!("Expected to unwrap a Number"),
        }
    }

    pub fn unwrap_boolean(self) -> bool {
        match self {
            ContextItem::Boolean(value) => value,
            _ => panic!("Expected to unwrap a Boolean"),
        }
    }
}

pub struct EvalContext {
    symbol_table: HashMap<String, ContextItem>,
}

impl EvalContext {
    pub fn new() -> EvalContext {
        EvalContext {
            symbol_table: HashMap::new(),
        }
    }

    pub fn prelude() -> EvalContext {
        let mut context = EvalContext::new();
        setup_prelude(&mut context);
        context
    }

    /// Gets a single value without evaluating it from the current context
    pub fn get(&self, name: &str) -> Option<ContextItem> {
        self.symbol_table.get(name).map(|item| (*item).clone())
    }

    /// Convenience method for setting a number in the context
    pub fn set_number(&mut self, name: &str, value: RichNumber) {
        self.set(name, ContextItem::Number(value))
    }

    /// Defines a function in the context
    pub fn define(&mut self, name: &str, fixity: Fixity, precedence: u8, function: Function) {
        debug_assert!(precedence >= LOWEST_PRECEDENCE && precedence <= HIGHEST_PRECEDENCE);

        self.set(name, ContextItem::Definition {
            fixity: fixity,
            precedence: precedence,
            function: function,
        })
    }

    /// Creates a constant value
    pub fn set_constant(&mut self, name: &str, value: String) {
        self.set(name, ContextItem::Constant(value));
    }

    /// Creates a boolean value
    pub fn set_boolean(&mut self, name: &str, value: bool) {
        self.set(name, ContextItem::Boolean(value));
    }

    /// Adds to the current context (silently replaces if already present)
    pub fn set(&mut self, name: &str, value: ContextItem) {
        self.symbol_table.insert(name.to_owned(), value);
    }

    pub fn apply(&mut self, statement: Statement) -> EvalResult {
        match statement {
            Statement::NamedFunction {name, definition} => {
                self.define(&name, Fixity::Prefix, FUNCTION_PRECEDENCE, definition);
                Ok(ContextItem::Nothing)
            },
            Statement::AnonymousFunction(_) => Ok(ContextItem::Nothing),
            Statement::Assignment {name, value} => {
                let value = try!(self.evaluate(value));
                self.set(&name, value);
                Ok(ContextItem::Nothing)
            },
            Statement::Expression(value) => self.evaluate(value),
        }
    }

    fn evaluate(&mut self, expr: Expr) -> EvalResult {
        unimplemented!();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ast::*;
    use api::parse;
    use rich_number::RichNumber;

    #[test]
    fn get_set_in_context() {
        let mut context = EvalContext::new();
        assert_eq!(context.get("a"), None);

        let value = RichNumber::from(2f64);
        context.set_number("a", value.clone());
        assert_eq!(context.get("a").map(|n| n.unwrap_number()), Some(value));
    }

    #[test]
    fn define_variable() {
        let mut context = EvalContext::new();
        apply_string(&mut context, "x = 3");

        assert_eq!(context.get("x").map(|n| n.unwrap_number()), Some(RichNumber::from(3f64)));
    }

    #[test]
    fn basic_operators_and_precedence() {
        let result = apply_single("2 * 3 ** 2 - (100e-1 + -77.2) / 13").unwrap();
        assert_eq!(result.unwrap_number(), RichNumber::from(23.1692307692f64));
    }

    fn test_single_boolean(string: &str, expected: bool) {
        let result = apply_single(string).unwrap();
        assert_eq!(result.unwrap_boolean(), expected);
    }

    fn apply_single(string: &str) -> EvalResult {
        let mut context = EvalContext::new();
        let statement = parse_statement(string);

        context.apply(statement)
    }

    fn parse_statement(string: &str) -> Statement {
        let mut parsed = parse(string).unwrap();
        assert!(parsed.len() == 1, "parse_statement() was passed more than one statement");

        parsed.pop().unwrap()
    }

    fn apply_string(mut context: &mut EvalContext, string: &str) {
        apply_program(context, parse(string).unwrap());
    }

    fn apply_program(mut context: &mut EvalContext, program: Program) {
        for statement in program {
            context.apply(statement).expect("Error while applying statement");
        }
    }
}

<commit_msg>Adding the ability to define a builtin function<commit_after>use std::collections::HashMap;

use ast::{Function, Expr, Statement};
use rich_number::RichNumber;
use prelude::setup_prelude;

const LOWEST_PRECEDENCE: u8 = 0;
const HIGHEST_PRECEDENCE: u8 = 9;
const FUNCTION_PRECEDENCE: u8 = HIGHEST_PRECEDENCE;

#[derive(PartialEq, Debug)]
pub enum EvalError {
    UnknownSymbol(String),
}

pub type EvalResult = Result<ContextItem, EvalError>;

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

#[derive(PartialEq, Debug, Clone)]
pub enum ContextItem {
    Number(RichNumber),
    Definition {
        // number from 0 to 9 where 9 is the highest precedence
        precedence: u8,
        fixity: Fixity,
        function: Function,
    },
    BuiltInMethod(fn(Vec<ContextItem>) -> EvalResult),
    Constant(String),
    Boolean(bool),
    Nothing,
}

impl ContextItem {
    pub fn unwrap_number(self) -> RichNumber {
        match self {
            ContextItem::Number(num) => num,
            _ => panic!("Expected to unwrap a Number"),
        }
    }

    pub fn unwrap_boolean(self) -> bool {
        match self {
            ContextItem::Boolean(value) => value,
            _ => panic!("Expected to unwrap a Boolean"),
        }
    }
}

pub struct EvalContext {
    symbol_table: HashMap<String, ContextItem>,
}

impl EvalContext {
    pub fn new() -> EvalContext {
        EvalContext {
            symbol_table: HashMap::new(),
        }
    }

    pub fn prelude() -> EvalContext {
        let mut context = EvalContext::new();
        setup_prelude(&mut context);
        context
    }

    /// Gets a single value without evaluating it from the current context
    pub fn get(&self, name: &str) -> Option<ContextItem> {
        self.symbol_table.get(name).map(|item| (*item).clone())
    }

    /// Convenience method for setting a number in the context
    pub fn set_number(&mut self, name: &str, value: RichNumber) {
        self.set(name, ContextItem::Number(value))
    }

    /// Defines a function in the context
    pub fn define(&mut self, name: &str, fixity: Fixity, precedence: u8, function: Function) {
        debug_assert!(precedence >= LOWEST_PRECEDENCE && precedence <= HIGHEST_PRECEDENCE);

        self.set(name, ContextItem::Definition {
            fixity: fixity,
            precedence: precedence,
            function: function,
        });
    }

    /// Defines a function linked to actual code rather than an expression
    pub fn define_builtin_method<F>(
        &mut self,
        name: &str,
        method: fn(Vec<ContextItem>
    ) -> EvalResult) {

        self.set(name, ContextItem::BuiltInMethod(method));
    }

    /// Creates a constant value
    pub fn set_constant(&mut self, name: &str, value: String) {
        self.set(name, ContextItem::Constant(value));
    }

    /// Creates a boolean value
    pub fn set_boolean(&mut self, name: &str, value: bool) {
        self.set(name, ContextItem::Boolean(value));
    }

    /// Adds to the current context (silently replaces if already present)
    pub fn set(&mut self, name: &str, value: ContextItem) {
        self.symbol_table.insert(name.to_owned(), value);
    }

    pub fn apply(&mut self, statement: Statement) -> EvalResult {
        match statement {
            Statement::NamedFunction {name, definition} => {
                self.define(&name, Fixity::Prefix, FUNCTION_PRECEDENCE, definition);
                Ok(ContextItem::Nothing)
            },
            Statement::AnonymousFunction(_) => Ok(ContextItem::Nothing),
            Statement::Assignment {name, value} => {
                let value = try!(self.evaluate(value));
                self.set(&name, value);
                Ok(ContextItem::Nothing)
            },
            Statement::Expression(value) => self.evaluate(value),
        }
    }

    fn evaluate(&mut self, expr: Expr) -> EvalResult {
        unimplemented!();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ast::*;
    use api::parse;
    use rich_number::RichNumber;

    #[test]
    fn get_set_in_context() {
        let mut context = EvalContext::new();
        assert_eq!(context.get("a"), None);

        let value = RichNumber::from(2f64);
        context.set_number("a", value.clone());
        assert_eq!(context.get("a").map(|n| n.unwrap_number()), Some(value));
    }

    #[test]
    fn define_variable() {
        let mut context = EvalContext::new();
        apply_string(&mut context, "x = 3");

        assert_eq!(context.get("x").map(|n| n.unwrap_number()), Some(RichNumber::from(3f64)));
    }

    #[test]
    fn basic_operators_and_precedence() {
        let result = apply_single("2 * 3 ** 2 - (100e-1 + -77.2) / 13").unwrap();
        assert_eq!(result.unwrap_number(), RichNumber::from(23.1692307692f64));
    }

    fn test_single_boolean(string: &str, expected: bool) {
        let result = apply_single(string).unwrap();
        assert_eq!(result.unwrap_boolean(), expected);
    }

    fn apply_single(string: &str) -> EvalResult {
        let mut context = EvalContext::new();
        let statement = parse_statement(string);

        context.apply(statement)
    }

    fn parse_statement(string: &str) -> Statement {
        let mut parsed = parse(string).unwrap();
        assert!(parsed.len() == 1, "parse_statement() was passed more than one statement");

        parsed.pop().unwrap()
    }

    fn apply_string(mut context: &mut EvalContext, string: &str) {
        apply_program(context, parse(string).unwrap());
    }

    fn apply_program(mut context: &mut EvalContext, program: Program) {
        for statement in program {
            context.apply(statement).expect("Error while applying statement");
        }
    }
}

<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Suppose we have the following data structure in a smart contract:
//!
//! struct B {
//!   Map<String, String> mymap;
//! }
//!
//! struct A {
//!   B b;
//!   int my_int;
//! }
//!
//! struct C {
//!   List<int> mylist;
//! }
//!
//! A a;
//! C c;
//!
//! and the data belongs to Alice. Then an access to `a.b.mymap` would be translated to an access
//! to an entry in key-value store whose key is `<Alice>/a/b/mymap`. In the same way, the access to
//! `c.mylist` would need to query `<Alice>/c/mylist`.
//!
//! So an account stores its data in a directory structure, for example:
//!   <Alice>/balance:   10
//!   <Alice>/a/b/mymap: {"Bob" => "abcd", "Carol" => "efgh"}
//!   <Alice>/a/myint:   20
//!   <Alice>/c/mylist:  [3, 5, 7, 9]
//!
//! If someone needs to query the map above and find out what value associated with "Bob" is,
//! `address` will be set to Alice and `path` will be set to "/a/b/mymap/Bob".
//!
//! On the other hand, if you want to query only <Alice>/a/*, `address` will be set to Alice and
//! `path` will be set to "/a" and use the `get_prefix()` method from statedb

use crate::{
    account_address::AccountAddress,
    account_config::{
        association_address, ACCOUNT_RECEIVED_EVENT_PATH, ACCOUNT_RESOURCE_PATH,
        ACCOUNT_SENT_EVENT_PATH,
    },
    identifier::{IdentStr, Identifier},
    language_storage::{ModuleId, ResourceKey, StructTag},
    validator_set::validator_set_path,
};
use anyhow::{Error, Result};
use libra_crypto::hash::{CryptoHash, HashValue};
use mirai_annotations::*;
use once_cell::sync::Lazy;
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use radix_trie::TrieKey;
use serde::{Deserialize, Serialize};
use std::{
    convert::{TryFrom, TryInto},
    fmt,
    slice::Iter,
};

#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
pub struct Field(Identifier);

impl Field {
    pub fn new(name: Identifier) -> Field {
        Field(name)
    }

    pub fn name(&self) -> &IdentStr {
        &self.0
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Eq, Hash, Serialize, Deserialize, Debug, Clone, PartialEq, Ord, PartialOrd)]
pub enum Access {
    Field(Field),
    Index(u64),
}

impl Access {
    pub fn new(name: Identifier) -> Self {
        Access::Field(Field::new(name))
    }
}

impl fmt::Display for Access {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Access::Field(field) => write!(f, "\"{}\"", field),
            Access::Index(i) => write!(f, "{}", i),
        }
    }
}

/// Non-empty sequence of field accesses
#[derive(Eq, Hash, Serialize, Deserialize, Debug, Clone, PartialEq, Ord, PartialOrd)]
pub struct Accesses(Vec<Access>);
// invariant self.0.len() == 1

/// SEPARATOR is used as a delimiter between fields. It should not be a legal part of any identifier
/// in the language
const SEPARATOR: char = '/';

impl Accesses {
    pub fn empty() -> Self {
        Accesses(vec![])
    }

    pub fn new(field: Field) -> Self {
        Accesses(vec![Access::Field(field)])
    }

    /// Add a field to the end of the sequence
    pub fn add_field_to_back(&mut self, field: Field) {
        self.0.push(Access::Field(field))
    }

    /// Add an index to the end of the sequence
    pub fn add_index_to_back(&mut self, idx: u64) {
        self.0.push(Access::Index(idx))
    }

    pub fn append(&mut self, accesses: &mut Accesses) {
        self.0.append(&mut accesses.0)
    }

    /// Returns the first field in the sequence and reference to the remaining fields
    pub fn split_first(&self) -> (&Access, &[Access]) {
        self.0.split_first().unwrap()
    }

    /// Return the last access in the sequence
    pub fn last(&self) -> &Access {
        assume!(self.0.last().is_some()); // follows from invariant
        self.0.last().unwrap() // guaranteed not to fail because sequence is non-empty
    }

    pub fn iter(&self) -> Iter<'_, Access> {
        self.0.iter()
    }

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

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn as_separated_string(&self) -> String {
        let mut path = String::new();
        for access in self.0.iter() {
            match access {
                Access::Field(s) => {
                    let access_str = s.name().as_str();
                    assert!(access_str != "");
                    path.push_str(access_str)
                }
                Access::Index(i) => path.push_str(i.to_string().as_ref()),
            };
            path.push(SEPARATOR);
        }
        path
    }

    pub fn take_nth(&self, new_len: usize) -> Accesses {
        assert!(self.0.len() >= new_len);
        Accesses(self.0.clone().into_iter().take(new_len).collect())
    }
}

impl<'a> IntoIterator for &'a Accesses {
    type Item = &'a Access;
    type IntoIter = Iter<'a, Access>;
    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl From<Vec<Access>> for Accesses {
    fn from(accesses: Vec<Access>) -> Accesses {
        Accesses(accesses)
    }
}

impl TrieKey for Accesses {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_separated_string().into_bytes()
    }
}

/// The access path where the Validator Set resource is stored.
pub static VALIDATOR_SET_ACCESS_PATH: Lazy<AccessPath> =
    Lazy::new(|| AccessPath::new(association_address(), validator_set_path()));

#[derive(Clone, Eq, PartialEq, Default, Hash, Serialize, Deserialize, Ord, PartialOrd)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct AccessPath {
    pub address: AccountAddress,
    pub path: Vec<u8>,
}

impl AccessPath {
    const CODE_TAG: u8 = 0;
    const RESOURCE_TAG: u8 = 1;

    pub fn new(address: AccountAddress, path: Vec<u8>) -> Self {
        AccessPath { address, path }
    }

    /// Given an address, returns the corresponding access path that stores the Account resource.
    pub fn new_for_account(address: AccountAddress) -> Self {
        Self::new(address, ACCOUNT_RESOURCE_PATH.to_vec())
    }

    /// Create an AccessPath for a ContractEvent.
    /// That is an AccessPah that uniquely identifies a given event for a published resource.
    pub fn new_for_event(address: AccountAddress, root: &[u8], key: &[u8]) -> Self {
        let mut path: Vec<u8> = Vec::new();
        path.extend_from_slice(root);
        path.push(b'/');
        path.extend_from_slice(key);
        path.push(b'/');
        Self::new(address, path)
    }

    /// Create an AccessPath to the event for the sender account in a deposit operation.
    /// The sent counter in LibraAccount.T (LibraAccount.T.sent_events_count) is used to generate
    /// the AccessPath.
    /// That AccessPath can be used as a key into the event storage to retrieve all sent
    /// events for a given account.
    pub fn new_for_sent_event(address: AccountAddress) -> Self {
        Self::new(address, ACCOUNT_SENT_EVENT_PATH.to_vec())
    }

    /// Create an AccessPath to the event for the target account (the receiver)
    /// in a deposit operation.
    /// The received counter in LibraAccount.T (LibraAccount.T.received_events_count) is used to
    /// generate the AccessPath.
    /// That AccessPath can be used as a key into the event storage to retrieve all received
    /// events for a given account.
    pub fn new_for_received_event(address: AccountAddress) -> Self {
        Self::new(address, ACCOUNT_RECEIVED_EVENT_PATH.to_vec())
    }

    pub fn resource_access_vec(tag: &StructTag, accesses: &Accesses) -> Vec<u8> {
        let mut key = vec![];
        key.push(Self::RESOURCE_TAG);

        key.append(&mut tag.hash().to_vec());

        // We don't need accesses in production right now. Accesses are appended here just for
        // passing the old tests.
        key.append(&mut accesses.as_separated_string().into_bytes());
        key
    }

    /// Convert Accesses into a byte offset which would be used by the storage layer to resolve
    /// where fields are stored.
    pub fn resource_access_path(key: &ResourceKey, accesses: &Accesses) -> AccessPath {
        let path = AccessPath::resource_access_vec(&key.type_(), accesses);
        AccessPath {
            address: key.address().to_owned(),
            path,
        }
    }

    fn code_access_path_vec(key: &ModuleId) -> Vec<u8> {
        let mut root = vec![];
        root.push(Self::CODE_TAG);
        root.append(&mut key.hash().to_vec());
        root
    }

    pub fn code_access_path(key: &ModuleId) -> AccessPath {
        let path = AccessPath::code_access_path_vec(key);
        AccessPath {
            address: *key.address(),
            path,
        }
    }
}

impl fmt::Debug for AccessPath {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "AccessPath {{ address: {:x}, path: {} }}",
            self.address,
            hex::encode(&self.path)
        )
    }
}

impl fmt::Display for AccessPath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.path.len() < 1 + HashValue::LENGTH {
            write!(f, "{:?}", self)
        } else {
            write!(f, "AccessPath {{ address: {:x}, ", self.address)?;
            match self.path[0] {
                Self::RESOURCE_TAG => write!(f, "type: Resource, ")?,
                Self::CODE_TAG => write!(f, "type: Module, ")?,
                tag => write!(f, "type: {:?}, ", tag)?,
            };
            write!(
                f,
                "hash: {:?}, ",
                hex::encode(&self.path[1..=HashValue::LENGTH])
            )?;
            write!(
                f,
                "suffix: {:?} }} ",
                String::from_utf8_lossy(&self.path[1 + HashValue::LENGTH..])
            )
        }
    }
}

impl TryFrom<crate::proto::types::AccessPath> for AccessPath {
    type Error = Error;

    fn try_from(proto: crate::proto::types::AccessPath) -> Result<Self> {
        Ok(AccessPath::new(proto.address.try_into()?, proto.path))
    }
}

impl From<AccessPath> for crate::proto::types::AccessPath {
    fn from(path: AccessPath) -> Self {
        Self {
            address: path.address.to_vec(),
            path: path.path,
        }
    }
}
<commit_msg>remove unused method `AccessPath::new_for_event()`<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! Suppose we have the following data structure in a smart contract:
//!
//! struct B {
//!   Map<String, String> mymap;
//! }
//!
//! struct A {
//!   B b;
//!   int my_int;
//! }
//!
//! struct C {
//!   List<int> mylist;
//! }
//!
//! A a;
//! C c;
//!
//! and the data belongs to Alice. Then an access to `a.b.mymap` would be translated to an access
//! to an entry in key-value store whose key is `<Alice>/a/b/mymap`. In the same way, the access to
//! `c.mylist` would need to query `<Alice>/c/mylist`.
//!
//! So an account stores its data in a directory structure, for example:
//!   <Alice>/balance:   10
//!   <Alice>/a/b/mymap: {"Bob" => "abcd", "Carol" => "efgh"}
//!   <Alice>/a/myint:   20
//!   <Alice>/c/mylist:  [3, 5, 7, 9]
//!
//! If someone needs to query the map above and find out what value associated with "Bob" is,
//! `address` will be set to Alice and `path` will be set to "/a/b/mymap/Bob".
//!
//! On the other hand, if you want to query only <Alice>/a/*, `address` will be set to Alice and
//! `path` will be set to "/a" and use the `get_prefix()` method from statedb

use crate::{
    account_address::AccountAddress,
    account_config::{
        association_address, ACCOUNT_RECEIVED_EVENT_PATH, ACCOUNT_RESOURCE_PATH,
        ACCOUNT_SENT_EVENT_PATH,
    },
    identifier::{IdentStr, Identifier},
    language_storage::{ModuleId, ResourceKey, StructTag},
    validator_set::validator_set_path,
};
use anyhow::{Error, Result};
use libra_crypto::hash::{CryptoHash, HashValue};
use mirai_annotations::*;
use once_cell::sync::Lazy;
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use radix_trie::TrieKey;
use serde::{Deserialize, Serialize};
use std::{
    convert::{TryFrom, TryInto},
    fmt,
    slice::Iter,
};

#[derive(Serialize, Deserialize, Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
pub struct Field(Identifier);

impl Field {
    pub fn new(name: Identifier) -> Field {
        Field(name)
    }

    pub fn name(&self) -> &IdentStr {
        &self.0
    }
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

#[derive(Eq, Hash, Serialize, Deserialize, Debug, Clone, PartialEq, Ord, PartialOrd)]
pub enum Access {
    Field(Field),
    Index(u64),
}

impl Access {
    pub fn new(name: Identifier) -> Self {
        Access::Field(Field::new(name))
    }
}

impl fmt::Display for Access {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Access::Field(field) => write!(f, "\"{}\"", field),
            Access::Index(i) => write!(f, "{}", i),
        }
    }
}

/// Non-empty sequence of field accesses
#[derive(Eq, Hash, Serialize, Deserialize, Debug, Clone, PartialEq, Ord, PartialOrd)]
pub struct Accesses(Vec<Access>);
// invariant self.0.len() == 1

/// SEPARATOR is used as a delimiter between fields. It should not be a legal part of any identifier
/// in the language
const SEPARATOR: char = '/';

impl Accesses {
    pub fn empty() -> Self {
        Accesses(vec![])
    }

    pub fn new(field: Field) -> Self {
        Accesses(vec![Access::Field(field)])
    }

    /// Add a field to the end of the sequence
    pub fn add_field_to_back(&mut self, field: Field) {
        self.0.push(Access::Field(field))
    }

    /// Add an index to the end of the sequence
    pub fn add_index_to_back(&mut self, idx: u64) {
        self.0.push(Access::Index(idx))
    }

    pub fn append(&mut self, accesses: &mut Accesses) {
        self.0.append(&mut accesses.0)
    }

    /// Returns the first field in the sequence and reference to the remaining fields
    pub fn split_first(&self) -> (&Access, &[Access]) {
        self.0.split_first().unwrap()
    }

    /// Return the last access in the sequence
    pub fn last(&self) -> &Access {
        assume!(self.0.last().is_some()); // follows from invariant
        self.0.last().unwrap() // guaranteed not to fail because sequence is non-empty
    }

    pub fn iter(&self) -> Iter<'_, Access> {
        self.0.iter()
    }

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

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }

    pub fn as_separated_string(&self) -> String {
        let mut path = String::new();
        for access in self.0.iter() {
            match access {
                Access::Field(s) => {
                    let access_str = s.name().as_str();
                    assert!(access_str != "");
                    path.push_str(access_str)
                }
                Access::Index(i) => path.push_str(i.to_string().as_ref()),
            };
            path.push(SEPARATOR);
        }
        path
    }

    pub fn take_nth(&self, new_len: usize) -> Accesses {
        assert!(self.0.len() >= new_len);
        Accesses(self.0.clone().into_iter().take(new_len).collect())
    }
}

impl<'a> IntoIterator for &'a Accesses {
    type Item = &'a Access;
    type IntoIter = Iter<'a, Access>;
    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl From<Vec<Access>> for Accesses {
    fn from(accesses: Vec<Access>) -> Accesses {
        Accesses(accesses)
    }
}

impl TrieKey for Accesses {
    fn encode_bytes(&self) -> Vec<u8> {
        self.as_separated_string().into_bytes()
    }
}

/// The access path where the Validator Set resource is stored.
pub static VALIDATOR_SET_ACCESS_PATH: Lazy<AccessPath> =
    Lazy::new(|| AccessPath::new(association_address(), validator_set_path()));

#[derive(Clone, Eq, PartialEq, Default, Hash, Serialize, Deserialize, Ord, PartialOrd)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct AccessPath {
    pub address: AccountAddress,
    pub path: Vec<u8>,
}

impl AccessPath {
    const CODE_TAG: u8 = 0;
    const RESOURCE_TAG: u8 = 1;

    pub fn new(address: AccountAddress, path: Vec<u8>) -> Self {
        AccessPath { address, path }
    }

    /// Given an address, returns the corresponding access path that stores the Account resource.
    pub fn new_for_account(address: AccountAddress) -> Self {
        Self::new(address, ACCOUNT_RESOURCE_PATH.to_vec())
    }

    /// Create an AccessPath to the event for the sender account in a deposit operation.
    /// The sent counter in LibraAccount.T (LibraAccount.T.sent_events_count) is used to generate
    /// the AccessPath.
    /// That AccessPath can be used as a key into the event storage to retrieve all sent
    /// events for a given account.
    pub fn new_for_sent_event(address: AccountAddress) -> Self {
        Self::new(address, ACCOUNT_SENT_EVENT_PATH.to_vec())
    }

    /// Create an AccessPath to the event for the target account (the receiver)
    /// in a deposit operation.
    /// The received counter in LibraAccount.T (LibraAccount.T.received_events_count) is used to
    /// generate the AccessPath.
    /// That AccessPath can be used as a key into the event storage to retrieve all received
    /// events for a given account.
    pub fn new_for_received_event(address: AccountAddress) -> Self {
        Self::new(address, ACCOUNT_RECEIVED_EVENT_PATH.to_vec())
    }

    pub fn resource_access_vec(tag: &StructTag, accesses: &Accesses) -> Vec<u8> {
        let mut key = vec![];
        key.push(Self::RESOURCE_TAG);

        key.append(&mut tag.hash().to_vec());

        // We don't need accesses in production right now. Accesses are appended here just for
        // passing the old tests.
        key.append(&mut accesses.as_separated_string().into_bytes());
        key
    }

    /// Convert Accesses into a byte offset which would be used by the storage layer to resolve
    /// where fields are stored.
    pub fn resource_access_path(key: &ResourceKey, accesses: &Accesses) -> AccessPath {
        let path = AccessPath::resource_access_vec(&key.type_(), accesses);
        AccessPath {
            address: key.address().to_owned(),
            path,
        }
    }

    fn code_access_path_vec(key: &ModuleId) -> Vec<u8> {
        let mut root = vec![];
        root.push(Self::CODE_TAG);
        root.append(&mut key.hash().to_vec());
        root
    }

    pub fn code_access_path(key: &ModuleId) -> AccessPath {
        let path = AccessPath::code_access_path_vec(key);
        AccessPath {
            address: *key.address(),
            path,
        }
    }
}

impl fmt::Debug for AccessPath {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "AccessPath {{ address: {:x}, path: {} }}",
            self.address,
            hex::encode(&self.path)
        )
    }
}

impl fmt::Display for AccessPath {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.path.len() < 1 + HashValue::LENGTH {
            write!(f, "{:?}", self)
        } else {
            write!(f, "AccessPath {{ address: {:x}, ", self.address)?;
            match self.path[0] {
                Self::RESOURCE_TAG => write!(f, "type: Resource, ")?,
                Self::CODE_TAG => write!(f, "type: Module, ")?,
                tag => write!(f, "type: {:?}, ", tag)?,
            };
            write!(
                f,
                "hash: {:?}, ",
                hex::encode(&self.path[1..=HashValue::LENGTH])
            )?;
            write!(
                f,
                "suffix: {:?} }} ",
                String::from_utf8_lossy(&self.path[1 + HashValue::LENGTH..])
            )
        }
    }
}

impl TryFrom<crate::proto::types::AccessPath> for AccessPath {
    type Error = Error;

    fn try_from(proto: crate::proto::types::AccessPath) -> Result<Self> {
        Ok(AccessPath::new(proto.address.try_into()?, proto.path))
    }
}

impl From<AccessPath> for crate::proto::types::AccessPath {
    fn from(path: AccessPath) -> Self {
        Self {
            address: path.address.to_vec(),
            path: path.path,
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use std::any::Any;

use super::super::{Element, ElementType, Family, InheritedProps, StyleProps, InstanceId,
                   ScriptsAndLimits, PropertyCalculator, Presentation, PresentationPrivate,
                   SpecifiedPresentationProps, EmptyComputeCtx, Property};
use ::platform::Context;
use ::layout::{Layout, MmultiscriptLayout};
use ::props::{Length, MathSize, PropertyModifier};

#[allow(const_err)]
const PROP_SUPERSCRIPT_SHIFT: Property<Length, Mmultiscripts, EmptyComputeCtx> = Property::Specified {
    default: || Length::Auto,
    reader: |i| i.superscript_shift(),
};

#[allow(const_err)]
const PROP_SUBSCRIPT_SHIFT: Property<Length, Mmultiscripts, EmptyComputeCtx> = Property::Specified {
    default: || Length::Auto,
    reader: |i| i.subscript_shift(),
};

pub struct Mmultiscript {
    pub superscript: Box<Element>,
    pub subscript: Box<Element>,
}

pub struct Mmultiscripts {
    base: Box<Element>,
    prescripts: Vec<Mmultiscript>,
    postscripts: Vec<Mmultiscript>,
    superscript_shift: Option<Length>,
    subscript_shift: Option<Length>,

    presentation_props: SpecifiedPresentationProps,

    instance_id: InstanceId,
}

impl Mmultiscripts {
    pub fn new(base: Box<Element>) -> Mmultiscripts {
        Mmultiscripts {
            base,
            prescripts: Vec::new(),
            postscripts: Vec::new(),
            superscript_shift: None,
            subscript_shift: None,
            presentation_props: SpecifiedPresentationProps::default(),
            instance_id: InstanceId::new(),
        }
    }

    pub fn with_base<'a>(&'a mut self, base: Box<Element>) -> &'a mut Mmultiscripts {
        self.base = base;
        self
    }

    pub fn base(&self) -> &Box<Element> {
        &self.base
    }

    pub fn with_prescript<'a>(&'a mut self, prescript: Mmultiscript) -> &'a mut Mmultiscripts {
        self.prescripts.push(prescript);
        self
    }

    pub fn prescript(&self) -> &[Mmultiscript] {
        &self.prescripts[..]
    }

    pub fn with_postscript<'a>(&'a mut self, postscript: Mmultiscript) -> &'a mut Mmultiscripts {
        self.postscripts.push(postscript);
        self
    }

    pub fn postscript(&self) -> &[Mmultiscript] {
        &self.postscripts[..]
    }

    pub fn with_superscript_shift<'a>(&'a mut self, superscript_shift: Option<Length>) -> &'a mut Mmultiscripts {
        self.superscript_shift = superscript_shift;
        self
    }

    pub fn superscript_shift(&self) -> Option<&Length> {
        self.superscript_shift.as_ref()
    }

    pub fn with_subscript_shift<'a>(&'a mut self, subscript_shift: Option<Length>) -> &'a mut Mmultiscripts {
        self.subscript_shift = subscript_shift;
        self
    }

    pub fn subscript_shift(&self) -> Option<&Length> {
        self.subscript_shift.as_ref()
    }
}

impl Element for Mmultiscripts {
    fn layout<'a>(&self, context: &Context, family: &Family<'a>, inherited: &InheritedProps,
                  style: &Option<&StyleProps>) -> Box<Layout> {
        let mut calculator = PropertyCalculator::new(
            context, self, family, inherited, style.clone());

        let presentation_layout = self.layout_presentation(&mut calculator);

        let superscript_shift = calculator.calculate(
            &PROP_SUPERSCRIPT_SHIFT, self.superscript_shift.as_ref());
        let subscript_shift = calculator.calculate(
            &PROP_SUBSCRIPT_SHIFT, self.subscript_shift.as_ref());
        let base_size = presentation_layout.script_level.get_font_size(context, &MathSize::NORMAL);

        let new_family = family.add(self);
        let inherited_fork = calculator.make_fork().copy();

        let mut inherited_fork_scripts = inherited_fork.copier();
        inherited_fork_scripts.display_style(false);
        inherited_fork_scripts.script_level(presentation_layout.script_level.new_level(
            PropertyModifier::Increment(1),
            context, &MathSize::NORMAL, presentation_layout.script_size_multiplier,
            presentation_layout.script_min_size
        ));
        let inherited_fork_scripts = inherited_fork_scripts.copy();

        Box::new(MmultiscriptLayout {
            base_layout: self.base.layout(context, &new_family, &inherited_fork, style),
            prescript_layout: self.prescripts.iter().map(| multiscript | {
                (
                    multiscript.superscript.layout(context, &new_family, &inherited_fork_scripts, style),
                    multiscript.subscript.layout(context, &new_family, &inherited_fork_scripts, style),
                )
            }).collect(),
            postscript_layout: self.postscripts.iter().map(| multiscript | {
                (
                    multiscript.superscript.layout(context, &new_family, &inherited_fork_scripts, style),
                    multiscript.subscript.layout(context, &new_family, &inherited_fork_scripts, style),
                )
            }).collect(),
            subscript_shift: subscript_shift.get_length_du(context, base_size),
            superscript_shift: superscript_shift.get_length_du(context, base_size),
            presentation_layout,
        })
    }

    fn type_info(&self) -> ElementType {
        ElementType::ScriptsAndLimits(ScriptsAndLimits::Mmutliscripts)
    }

    fn as_any(&self) -> &Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self
    }

    fn instance_id(&self) -> &InstanceId {
        &self.instance_id
    }
}

impl PresentationPrivate<Mmultiscripts> for Mmultiscripts {
    fn get_specified_presentation_props(&self) -> &SpecifiedPresentationProps {
        &self.presentation_props
    }

    fn get_specified_presentation_props_mut(&mut self) -> &mut SpecifiedPresentationProps {
        &mut self.presentation_props
    }
}

impl Presentation<Mmultiscripts> for Mmultiscripts {}

#[cfg(test)]
mod test {
    use super::*;
    use ::elements::*;
    use ::props::*;
    use ::test::skia::Snapshot;

    #[test]
    fn it_works() {
        let snapshot = Snapshot::default();

        let mut script = Mmultiscripts::new(Box::new(Mi::new(String::from("x"))));
        snapshot.snap_element(&script, "mmutliscript_base_only");

        script.with_prescript(
            Mmultiscript {
                superscript: Box::new(Mn::new(String::from("1"))),
                subscript: Box::new(Mn::new(String::from("2")))
            }
        );

        snapshot.snap_element(&script, "mmutliscript_prescript_only");

        script.with_postscript(
            Mmultiscript {
                superscript: Box::new(Mn::new(String::from("3"))),
                subscript: Box::new(Mn::new(String::from("4")))
            }
        );

        snapshot.snap_element(&script, "mmutliscript_prescript_postscript");

        script.with_postscript(
            Mmultiscript {
                superscript: Box::new(Msub::new(
                    Box::new(Mi::new(String::from("a"))),
                    Box::new(Msub::new(
                        Box::new(Mi::new(String::from("a"))),
                        Box::new(Msub::new(
                            Box::new(Mi::new(String::from("a"))),
                            Box::new(Msub::new(
                                Box::new(Mi::new(String::from("a"))),
                                Box::new(Mi::new(String::from("i")))
                            ))
                        ))
                    ))
                )),
                subscript: Box::new(Mn::new(String::from("4")))
            }
        );

        snapshot.snap_element(&script, "mmutliscript_prescript_postscript_diff_height");
    }
}<commit_msg>Add test for math color and math background<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use std::any::Any;

use super::super::{Element, ElementType, Family, InheritedProps, StyleProps, InstanceId,
                   ScriptsAndLimits, PropertyCalculator, Presentation, PresentationPrivate,
                   SpecifiedPresentationProps, EmptyComputeCtx, Property};
use ::platform::Context;
use ::layout::{Layout, MmultiscriptLayout};
use ::props::{Length, MathSize, PropertyModifier};

#[allow(const_err)]
const PROP_SUPERSCRIPT_SHIFT: Property<Length, Mmultiscripts, EmptyComputeCtx> = Property::Specified {
    default: || Length::Auto,
    reader: |i| i.superscript_shift(),
};

#[allow(const_err)]
const PROP_SUBSCRIPT_SHIFT: Property<Length, Mmultiscripts, EmptyComputeCtx> = Property::Specified {
    default: || Length::Auto,
    reader: |i| i.subscript_shift(),
};

pub struct Mmultiscript {
    pub superscript: Box<Element>,
    pub subscript: Box<Element>,
}

pub struct Mmultiscripts {
    base: Box<Element>,
    prescripts: Vec<Mmultiscript>,
    postscripts: Vec<Mmultiscript>,
    superscript_shift: Option<Length>,
    subscript_shift: Option<Length>,

    presentation_props: SpecifiedPresentationProps,

    instance_id: InstanceId,
}

impl Mmultiscripts {
    pub fn new(base: Box<Element>) -> Mmultiscripts {
        Mmultiscripts {
            base,
            prescripts: Vec::new(),
            postscripts: Vec::new(),
            superscript_shift: None,
            subscript_shift: None,
            presentation_props: SpecifiedPresentationProps::default(),
            instance_id: InstanceId::new(),
        }
    }

    pub fn with_base<'a>(&'a mut self, base: Box<Element>) -> &'a mut Mmultiscripts {
        self.base = base;
        self
    }

    pub fn base(&self) -> &Box<Element> {
        &self.base
    }

    pub fn with_prescript<'a>(&'a mut self, prescript: Mmultiscript) -> &'a mut Mmultiscripts {
        self.prescripts.push(prescript);
        self
    }

    pub fn prescript(&self) -> &[Mmultiscript] {
        &self.prescripts[..]
    }

    pub fn with_postscript<'a>(&'a mut self, postscript: Mmultiscript) -> &'a mut Mmultiscripts {
        self.postscripts.push(postscript);
        self
    }

    pub fn postscript(&self) -> &[Mmultiscript] {
        &self.postscripts[..]
    }

    pub fn with_superscript_shift<'a>(&'a mut self, superscript_shift: Option<Length>) -> &'a mut Mmultiscripts {
        self.superscript_shift = superscript_shift;
        self
    }

    pub fn superscript_shift(&self) -> Option<&Length> {
        self.superscript_shift.as_ref()
    }

    pub fn with_subscript_shift<'a>(&'a mut self, subscript_shift: Option<Length>) -> &'a mut Mmultiscripts {
        self.subscript_shift = subscript_shift;
        self
    }

    pub fn subscript_shift(&self) -> Option<&Length> {
        self.subscript_shift.as_ref()
    }
}

impl Element for Mmultiscripts {
    fn layout<'a>(&self, context: &Context, family: &Family<'a>, inherited: &InheritedProps,
                  style: &Option<&StyleProps>) -> Box<Layout> {
        let mut calculator = PropertyCalculator::new(
            context, self, family, inherited, style.clone());

        let presentation_layout = self.layout_presentation(&mut calculator);

        let superscript_shift = calculator.calculate(
            &PROP_SUPERSCRIPT_SHIFT, self.superscript_shift.as_ref());
        let subscript_shift = calculator.calculate(
            &PROP_SUBSCRIPT_SHIFT, self.subscript_shift.as_ref());
        let base_size = presentation_layout.script_level.get_font_size(context, &MathSize::NORMAL);

        let new_family = family.add(self);
        let inherited_fork = calculator.make_fork().copy();

        let mut inherited_fork_scripts = inherited_fork.copier();
        inherited_fork_scripts.display_style(false);
        inherited_fork_scripts.script_level(presentation_layout.script_level.new_level(
            PropertyModifier::Increment(1),
            context, &MathSize::NORMAL, presentation_layout.script_size_multiplier,
            presentation_layout.script_min_size
        ));
        let inherited_fork_scripts = inherited_fork_scripts.copy();

        Box::new(MmultiscriptLayout {
            base_layout: self.base.layout(context, &new_family, &inherited_fork, style),
            prescript_layout: self.prescripts.iter().map(| multiscript | {
                (
                    multiscript.superscript.layout(context, &new_family, &inherited_fork_scripts, style),
                    multiscript.subscript.layout(context, &new_family, &inherited_fork_scripts, style),
                )
            }).collect(),
            postscript_layout: self.postscripts.iter().map(| multiscript | {
                (
                    multiscript.superscript.layout(context, &new_family, &inherited_fork_scripts, style),
                    multiscript.subscript.layout(context, &new_family, &inherited_fork_scripts, style),
                )
            }).collect(),
            subscript_shift: subscript_shift.get_length_du(context, base_size),
            superscript_shift: superscript_shift.get_length_du(context, base_size),
            presentation_layout,
        })
    }

    fn type_info(&self) -> ElementType {
        ElementType::ScriptsAndLimits(ScriptsAndLimits::Mmutliscripts)
    }

    fn as_any(&self) -> &Any {
        self
    }

    fn as_any_mut(&mut self) -> &mut Any {
        self
    }

    fn instance_id(&self) -> &InstanceId {
        &self.instance_id
    }
}

impl PresentationPrivate<Mmultiscripts> for Mmultiscripts {
    fn get_specified_presentation_props(&self) -> &SpecifiedPresentationProps {
        &self.presentation_props
    }

    fn get_specified_presentation_props_mut(&mut self) -> &mut SpecifiedPresentationProps {
        &mut self.presentation_props
    }
}

impl Presentation<Mmultiscripts> for Mmultiscripts {}

#[cfg(test)]
mod test {
    use super::*;
    use ::elements::*;
    use ::props::*;
    use ::test::skia::Snapshot;

    #[test]
    fn it_works() {
        let snapshot = Snapshot::default();

        let mut script = Mmultiscripts::new(Box::new(Mi::new(String::from("x"))));
        snapshot.snap_element(&script, "mmutliscript_base_only");

        script.with_prescript(
            Mmultiscript {
                superscript: Box::new(Mn::new(String::from("1"))),
                subscript: Box::new(Mn::new(String::from("2")))
            }
        );

        snapshot.snap_element(&script, "mmutliscript_prescript_only");

        script.with_postscript(
            Mmultiscript {
                superscript: Box::new(Mn::new(String::from("3"))),
                subscript: Box::new(Mn::new(String::from("4")))
            }
        );

        snapshot.snap_element(&script, "mmutliscript_prescript_postscript");

        script.with_math_color(Some(Color::RGB(0, 255, 255)));
        script.with_math_background(Some(Color::RGB(0, 0, 0)));

        snapshot.snap_element(&script, "mmutliscript_math_color_sky_blue_bg_black");

        script.with_postscript(
            Mmultiscript {
                superscript: Box::new(Msub::new(
                    Box::new(Mi::new(String::from("a"))),
                    Box::new(Msub::new(
                        Box::new(Mi::new(String::from("a"))),
                        Box::new(Msub::new(
                            Box::new(Mi::new(String::from("a"))),
                            Box::new(Msub::new(
                                Box::new(Mi::new(String::from("a"))),
                                Box::new(Mi::new(String::from("i")))
                            ))
                        ))
                    ))
                )),
                subscript: Box::new(Mn::new(String::from("4")))
            }
        );

        snapshot.snap_element(&script, "mmutliscript_prescript_postscript_diff_height");
    }
}<|endoftext|>


<commit_before>use crate::{Command, CommandBoxClone, WorkOption, WorkResult};
use color_printer::{Color, ColorPrinter, ColorSpec};
use command_derive::CommandBoxClone;
use gitlib::GitRepo;
use std::{io::Write, path::PathBuf};

#[derive(Clone, CommandBoxClone, Default)]
pub struct FetchCommand;

impl FetchCommand {
    pub fn new() -> Self {
        Self {}
    }
}

struct FetchCommandResult {}

impl Command for FetchCommand {
    fn process(&self, repo: GitRepo) -> WorkOption {
        Some(Box::new(FetchCommandResult {}))
    }
}

impl WorkResult for FetchCommandResult {
    fn print(&self, printer: &mut ColorPrinter<'_>) {}
}
<commit_msg>Fetch progress<commit_after>use crate::{Command, CommandBoxClone, WorkOption, WorkResult};
use color_printer::{Color, ColorPrinter, ColorSpec};
use command_derive::CommandBoxClone;
use gitlib::GitRepo;
use std::{io::Write, path::PathBuf};

#[derive(Clone, CommandBoxClone, Default)]
pub struct FetchCommand;

impl FetchCommand {
    pub fn new() -> Self {
        Self {}
    }
}

struct FetchCommandResult {
    msg: String,
}

impl Command for FetchCommand {
    fn process(&self, repo: GitRepo) -> WorkOption {
        let res = match repo.fetch() {
            Ok(_) => Box::new(FetchCommandResult {
                msg: "My man!".into(),
            }),
            Err(_) => Box::new(FetchCommandResult {
                msg: "Not like this".into(),
            }),
        };

        Some(res)
    }
}

impl WorkResult for FetchCommandResult {
    fn print(&self, printer: &mut ColorPrinter<'_>) {
        writeln!(printer, "{}", self.msg).expect("write fail");
    }
}
<|endoftext|>