<commit_before>pub use self::tokens::{Doctype, Attributes, TagKind, StartTag, EndTag, Tag, Token};
pub use self::tokens::{DoctypeToken, TagToken, CommentToken, CharacterToken};

use self::states::{RawLessThanSign, RawEndTagOpen, RawEndTagName};
use self::states::{Rcdata, ScriptData, ScriptDataEscaped};

mod tokens;
mod states;

pub trait TokenSink {
    fn process_token(&mut self, token: Token);
}

fn ascii_letter(c: char) -> Option<char> {
    c.to_ascii_opt()
        .filtered(|a| a.is_alpha())
        .map(|a| a.to_lower().to_char())
}

pub struct Tokenizer<'sink, Sink> {
    priv sink: &'sink mut Sink,
    priv state: states::State,

    // FIXME: The state machine guarantees the tag exists when
    // we need it, so we could eliminate the Option overhead.
    // Leaving it as Option for now, to find bugs.
    priv current_tag: Option<Tag>,

    /// Last start tag name, for use in checking "appropriate end tag".
    priv last_start_tag_name: Option<~str>,

    /// The "temporary buffer" mentioned in the spec.
    priv temp_buf: ~str
}

#[deriving(Eq)]
enum ConsumeCharResult {
    Reconsume,
    Finished,
}

impl<'sink, Sink: TokenSink> Tokenizer<'sink, Sink> {
    pub fn new(sink: &'sink mut Sink) -> Tokenizer<'sink, Sink> {
        Tokenizer {
            sink: sink,
            state: states::Data,
            current_tag: None,
            last_start_tag_name: None,
            temp_buf: ~"",
        }
    }

    pub fn feed(&mut self, input: &str) {
        debug!("feeding {:s}", input);
        let mut it = input.chars(); //.peekable();
        loop {
            match self.state {
                // These states do something other than consume a single character.
                states::CharacterReferenceInData | states::CharacterReferenceInRcdata
                | states::CharacterReferenceInAttributeValue | states::BogusComment
                | states::MarkupDeclarationOpen | states::CdataSection => {
                    fail!("FIXME: state {:?} not implemented", self.state);
                }

                _ => match it.next() {
                    None => return,
                    Some(c) => {
                        while self.process_char(c) == Reconsume {
                            // FIXME: this is not correct when state changes to one
                            // of the above!
                        }
                    }
                }
            }
        }
    }

    fn parse_error(&self, c: char) {
        error!("Parse error: saw {:?} in state {:?}", c, self.state);
    }

    fn emit_char(&self, c: char) {
        self.sink.process_token(CharacterToken(c));
    }

    fn emit_current_tag(&mut self) {
        let tag = self.current_tag.take().unwrap();
        match tag.kind {
            StartTag => self.last_start_tag_name = Some(tag.name.clone()),
            _ => ()
        }
        self.sink.process_token(TagToken(tag));
    }

    fn emit_temp_buf(&mut self) {
        // FIXME: Add a multi-character token and move temp_buf into it, something like
        //     self.sink.process_token(StringToken(
        //         replace(&mut self.temp_buf, ~"")))
        //
        // Need to make sure that clearing on emit is spec-compatible.
        //
        // Until then we reuse the same buffer allocation forever.
        for c in self.temp_buf.chars() {
            self.emit_char(c);
        }
    }

    fn clear_temp_buf(&mut self) {
        // Do this without a new allocation.
        self.temp_buf.truncate(0);
    }

    fn create_tag(&mut self, kind: TagKind, c: char) {
        assert!(self.current_tag.is_none());
        let mut t = Tag::new(kind);
        t.name.push_char(c);
        self.current_tag = Some(t);
    }

    fn append_to_tag_name(&mut self, c: char) {
        self.current_tag.get_mut_ref().name.push_char(c);
    }

    fn have_appropriate_end_tag(&self) -> bool {
        match (self.last_start_tag_name.as_ref(), self.current_tag.as_ref()) {
            (Some(last), Some(tag)) =>
                (tag.kind == EndTag) && (tag.name.as_slice() == last.as_slice()),
            _ => false
        }
    }
}

// Shorthand for common state machine behaviors.
macro_rules! shorthand (
    ( to          $state:ident             ) => ( self.state = states::$state;        );
    ( to_raw      $state:ident $kind:ident ) => ( self.state = states::$state($kind); );
    ( emit        $c:expr                  ) => ( self.emit_char($c);                 );
    ( create_tag  $kind:expr   $c:expr     ) => ( self.create_tag($kind, $c);         );
    ( append_tag  $c:expr                  ) => ( self.append_to_tag_name($c);        );
    ( emit_tag                             ) => ( self.emit_current_tag();            );
    ( append_temp $c:expr                  ) => ( self.temp_buf.push_char($c);        );
    ( emit_temp                            ) => ( self.emit_temp_buf();               );
    ( clear_temp                           ) => ( self.clear_temp_buf();              );

    // NB: Deliberate capture of 'c'
    ( error                                ) => ( self.parse_error(c);                );
)

// A little DSL for sequencing shorthand actions.
macro_rules! go (
    // A pattern like $($cmd:tt)* ; $($rest:tt)* causes parse ambiguity.
    // We have to tell the parser how much lookahead we need.
    ( $a:tt             ; $($rest:tt)* ) => ({ shorthand!($a);       go!($($rest)*); });
    ( $a:tt $b:tt       ; $($rest:tt)* ) => ({ shorthand!($a $b);    go!($($rest)*); });
    ( $a:tt $b:tt $c:tt ; $($rest:tt)* ) => ({ shorthand!($a $b $c); go!($($rest)*); });

    // These can only come at the end.
    // FIXME: Come up with a better name for 'finish'.
    ( reconsume ) => ( return Reconsume; );
    ( finish    ) => ( return Finished;  );

    // If nothing else matched, it's a single command
    ( $($cmd:tt)+ ) => ( shorthand!($($cmd)+); );

    // or nothing.
    () => (());
)

impl<'sink, Sink: TokenSink> Tokenizer<'sink, Sink> {
    // FIXME: explicitly represent the EOF character?
    // For now the plan is to handle EOF in a separate match.
    fn process_char(&mut self, c: char) -> ConsumeCharResult {
        debug!("Processing {:?} in state {:?}", c, self.state);
        match self.state {
            states::Data => match c {
                '&'  => go!(to CharacterReferenceInData),
                '<'  => go!(to TagOpen),
                '\0' => go!(error; emit '\0'),
                _    => go!(emit c),
            },

            // RCDATA, RAWTEXT, script, or script escaped
            states::RawData(kind) => match c {
                '&' if kind == Rcdata            => go!(to CharacterReferenceInRcdata),
                '-' if kind == ScriptDataEscaped => go!(to ScriptDataEscapedDash; emit '-'),
                '<'  => go!(to_raw RawLessThanSign kind),
                '\0' => go!(error; emit '\ufffd'),
                _    => go!(emit c),
            },

            states::Plaintext => match c {
                '\0' => go!(error; emit '\ufffd'),
                _    => go!(emit c),
            },

            states::TagOpen => match c {
                '!' => go!(to MarkupDeclarationOpen),
                '/' => go!(to EndTagOpen),
                '?' => go!(error; to BogusComment),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(create_tag StartTag cl; to TagName),
                    None     => go!(error; emit '<'; to Data; reconsume),
                }
            },

            states::EndTagOpen => match c {
                '>' => go!(error; to Data),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(create_tag EndTag cl; to TagName),
                    None     => go!(error; to BogusComment),
                }
            },

            states::TagName => match c {
                '\t' | '\n' | '\x0C' | ' '
                     => go!(to BeforeAttributeName),
                '/'  => go!(to SelfClosingStartTag),
                '>'  => go!(emit_tag; to Data),
                '\0' => go!(error; append_tag '\ufffd'),
                _    => go!(append_tag (ascii_letter(c).unwrap_or(c))),
            },

            // kind = ScriptDataEscaped
            states::RawLessThanSign(ScriptDataEscaped) => match c {
                '/' => go!(clear_temp; to_raw RawEndTagOpen ScriptDataEscaped),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(clear_temp; append_temp cl;
                                    to ScriptDataDoubleEscapeStart; emit '<'; emit c),
                    None => go!(to_raw RawData ScriptDataEscaped; emit '<'; reconsume),
                }
            },

            // otherwise
            states::RawLessThanSign(kind) => match c {
                '/' => go!(clear_temp; to_raw RawEndTagOpen kind),
                '!' if kind == ScriptData => go!(to ScriptDataEscapeStart; emit '<'; emit '!'),
                _   => go!(to_raw RawData Rcdata; emit '<'; reconsume),
            },

            states::RawEndTagOpen(kind) => match ascii_letter(c) {
                Some(cl) => go!(create_tag EndTag cl; append_temp c; to_raw RawEndTagName kind),
                None     => go!(to_raw RawData kind; emit '<'; emit '/'; reconsume),
            },

            states::RawEndTagName(kind) => {
                if self.have_appropriate_end_tag() {
                    match c {
                        '\t' | '\n' | '\x0C' | ' '
                            => go!(to BeforeAttributeName; finish),
                        '/' => go!(to SelfClosingStartTag; finish),
                        '>' => go!(emit_tag; to Data; finish),
                        // All of the above end with a return from this function.

                        _ => (),
                    }
                }

                match ascii_letter(c) {
                    Some(cl) => go!(append_tag cl; append_temp c),
                    None     => go!(emit '<'; emit '/'; emit_temp; to_raw RawData kind; reconsume),
                }
            },

            s => fail!("FIXME: state {:?} not implemented", s),
        }

        Finished

    }
}
<commit_msg>List the unimplemented states<commit_after>pub use self::tokens::{Doctype, Attributes, TagKind, StartTag, EndTag, Tag, Token};
pub use self::tokens::{DoctypeToken, TagToken, CommentToken, CharacterToken};

use self::states::{RawLessThanSign, RawEndTagOpen, RawEndTagName};
use self::states::{Rcdata, ScriptData, ScriptDataEscaped};

mod tokens;
mod states;

pub trait TokenSink {
    fn process_token(&mut self, token: Token);
}

fn ascii_letter(c: char) -> Option<char> {
    c.to_ascii_opt()
        .filtered(|a| a.is_alpha())
        .map(|a| a.to_lower().to_char())
}

pub struct Tokenizer<'sink, Sink> {
    priv sink: &'sink mut Sink,
    priv state: states::State,

    // FIXME: The state machine guarantees the tag exists when
    // we need it, so we could eliminate the Option overhead.
    // Leaving it as Option for now, to find bugs.
    priv current_tag: Option<Tag>,

    /// Last start tag name, for use in checking "appropriate end tag".
    priv last_start_tag_name: Option<~str>,

    /// The "temporary buffer" mentioned in the spec.
    priv temp_buf: ~str
}

#[deriving(Eq)]
enum ConsumeCharResult {
    Reconsume,
    Finished,
}

impl<'sink, Sink: TokenSink> Tokenizer<'sink, Sink> {
    pub fn new(sink: &'sink mut Sink) -> Tokenizer<'sink, Sink> {
        Tokenizer {
            sink: sink,
            state: states::Data,
            current_tag: None,
            last_start_tag_name: None,
            temp_buf: ~"",
        }
    }

    pub fn feed(&mut self, input: &str) {
        debug!("feeding {:s}", input);
        let mut it = input.chars(); //.peekable();
        loop {
            match self.state {
                // These states do something other than consume a single character.
                states::CharacterReferenceInData | states::CharacterReferenceInRcdata
                | states::CharacterReferenceInAttributeValue | states::BogusComment
                | states::MarkupDeclarationOpen | states::CdataSection => {
                    fail!("FIXME: state {:?} not implemented", self.state);
                }

                _ => match it.next() {
                    None => return,
                    Some(c) => {
                        while self.process_char(c) == Reconsume {
                            // FIXME: this is not correct when state changes to one
                            // of the above!
                        }
                    }
                }
            }
        }
    }

    fn parse_error(&self, c: char) {
        error!("Parse error: saw {:?} in state {:?}", c, self.state);
    }

    fn emit_char(&self, c: char) {
        self.sink.process_token(CharacterToken(c));
    }

    fn emit_current_tag(&mut self) {
        let tag = self.current_tag.take().unwrap();
        match tag.kind {
            StartTag => self.last_start_tag_name = Some(tag.name.clone()),
            _ => ()
        }
        self.sink.process_token(TagToken(tag));
    }

    fn emit_temp_buf(&mut self) {
        // FIXME: Add a multi-character token and move temp_buf into it, something like
        //     self.sink.process_token(StringToken(
        //         replace(&mut self.temp_buf, ~"")))
        //
        // Need to make sure that clearing on emit is spec-compatible.
        //
        // Until then we reuse the same buffer allocation forever.
        for c in self.temp_buf.chars() {
            self.emit_char(c);
        }
    }

    fn clear_temp_buf(&mut self) {
        // Do this without a new allocation.
        self.temp_buf.truncate(0);
    }

    fn create_tag(&mut self, kind: TagKind, c: char) {
        assert!(self.current_tag.is_none());
        let mut t = Tag::new(kind);
        t.name.push_char(c);
        self.current_tag = Some(t);
    }

    fn append_to_tag_name(&mut self, c: char) {
        self.current_tag.get_mut_ref().name.push_char(c);
    }

    fn have_appropriate_end_tag(&self) -> bool {
        match (self.last_start_tag_name.as_ref(), self.current_tag.as_ref()) {
            (Some(last), Some(tag)) =>
                (tag.kind == EndTag) && (tag.name.as_slice() == last.as_slice()),
            _ => false
        }
    }
}

// Shorthand for common state machine behaviors.
macro_rules! shorthand (
    ( to          $state:ident             ) => ( self.state = states::$state;        );
    ( to_raw      $state:ident $kind:ident ) => ( self.state = states::$state($kind); );
    ( emit        $c:expr                  ) => ( self.emit_char($c);                 );
    ( create_tag  $kind:expr   $c:expr     ) => ( self.create_tag($kind, $c);         );
    ( append_tag  $c:expr                  ) => ( self.append_to_tag_name($c);        );
    ( emit_tag                             ) => ( self.emit_current_tag();            );
    ( append_temp $c:expr                  ) => ( self.temp_buf.push_char($c);        );
    ( emit_temp                            ) => ( self.emit_temp_buf();               );
    ( clear_temp                           ) => ( self.clear_temp_buf();              );

    // NB: Deliberate capture of 'c'
    ( error                                ) => ( self.parse_error(c);                );
)

// A little DSL for sequencing shorthand actions.
macro_rules! go (
    // A pattern like $($cmd:tt)* ; $($rest:tt)* causes parse ambiguity.
    // We have to tell the parser how much lookahead we need.
    ( $a:tt             ; $($rest:tt)* ) => ({ shorthand!($a);       go!($($rest)*); });
    ( $a:tt $b:tt       ; $($rest:tt)* ) => ({ shorthand!($a $b);    go!($($rest)*); });
    ( $a:tt $b:tt $c:tt ; $($rest:tt)* ) => ({ shorthand!($a $b $c); go!($($rest)*); });

    // These can only come at the end.
    // FIXME: Come up with a better name for 'finish'.
    ( reconsume ) => ( return Reconsume; );
    ( finish    ) => ( return Finished;  );

    // If nothing else matched, it's a single command
    ( $($cmd:tt)+ ) => ( shorthand!($($cmd)+); );

    // or nothing.
    () => (());
)

impl<'sink, Sink: TokenSink> Tokenizer<'sink, Sink> {
    // FIXME: explicitly represent the EOF character?
    // For now the plan is to handle EOF in a separate match.
    fn process_char(&mut self, c: char) -> ConsumeCharResult {
        debug!("Processing {:?} in state {:?}", c, self.state);
        match self.state {
            states::Data => match c {
                '&'  => go!(to CharacterReferenceInData),
                '<'  => go!(to TagOpen),
                '\0' => go!(error; emit '\0'),
                _    => go!(emit c),
            },

            // RCDATA, RAWTEXT, script, or script escaped
            states::RawData(kind) => match c {
                '&' if kind == Rcdata            => go!(to CharacterReferenceInRcdata),
                '-' if kind == ScriptDataEscaped => go!(to ScriptDataEscapedDash; emit '-'),
                '<'  => go!(to_raw RawLessThanSign kind),
                '\0' => go!(error; emit '\ufffd'),
                _    => go!(emit c),
            },

            states::Plaintext => match c {
                '\0' => go!(error; emit '\ufffd'),
                _    => go!(emit c),
            },

            states::TagOpen => match c {
                '!' => go!(to MarkupDeclarationOpen),
                '/' => go!(to EndTagOpen),
                '?' => go!(error; to BogusComment),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(create_tag StartTag cl; to TagName),
                    None     => go!(error; emit '<'; to Data; reconsume),
                }
            },

            states::EndTagOpen => match c {
                '>' => go!(error; to Data),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(create_tag EndTag cl; to TagName),
                    None     => go!(error; to BogusComment),
                }
            },

            states::TagName => match c {
                '\t' | '\n' | '\x0C' | ' '
                     => go!(to BeforeAttributeName),
                '/'  => go!(to SelfClosingStartTag),
                '>'  => go!(emit_tag; to Data),
                '\0' => go!(error; append_tag '\ufffd'),
                _    => go!(append_tag (ascii_letter(c).unwrap_or(c))),
            },

            // kind = ScriptDataEscaped
            states::RawLessThanSign(ScriptDataEscaped) => match c {
                '/' => go!(clear_temp; to_raw RawEndTagOpen ScriptDataEscaped),
                _ => match ascii_letter(c) {
                    Some(cl) => go!(clear_temp; append_temp cl;
                                    to ScriptDataDoubleEscapeStart; emit '<'; emit c),
                    None => go!(to_raw RawData ScriptDataEscaped; emit '<'; reconsume),
                }
            },

            // otherwise
            states::RawLessThanSign(kind) => match c {
                '/' => go!(clear_temp; to_raw RawEndTagOpen kind),
                '!' if kind == ScriptData => go!(to ScriptDataEscapeStart; emit '<'; emit '!'),
                _   => go!(to_raw RawData Rcdata; emit '<'; reconsume),
            },

            states::RawEndTagOpen(kind) => match ascii_letter(c) {
                Some(cl) => go!(create_tag EndTag cl; append_temp c; to_raw RawEndTagName kind),
                None     => go!(to_raw RawData kind; emit '<'; emit '/'; reconsume),
            },

            states::RawEndTagName(kind) => {
                if self.have_appropriate_end_tag() {
                    match c {
                        '\t' | '\n' | '\x0C' | ' '
                            => go!(to BeforeAttributeName; finish),
                        '/' => go!(to SelfClosingStartTag; finish),
                        '>' => go!(emit_tag; to Data; finish),
                        // All of the above end with a return from this function.

                        _ => (),
                    }
                }

                match ascii_letter(c) {
                    Some(cl) => go!(append_tag cl; append_temp c),
                    None     => go!(emit '<'; emit '/'; emit_temp; to_raw RawData kind; reconsume),
                }
            },

            states::ScriptDataEscapeStart |
            states::ScriptDataEscapeStartDash |
            states::ScriptDataEscapedDash |
            states::ScriptDataEscapedDashDash |
            states::ScriptDataDoubleEscapeStart |
            states::ScriptDataDoubleEscaped |
            states::ScriptDataDoubleEscapedDash |
            states::ScriptDataDoubleEscapedDashDash |
            states::ScriptDataDoubleEscapedLessThanSign |
            states::ScriptDataDoubleEscapeEnd |
            states::BeforeAttributeName |
            states::AttributeName |
            states::AfterAttributeName |
            states::BeforeAttributeValue |
            states::AttributeValueDoubleQuoted |
            states::AttributeValueSingleQuoted |
            states::AttributeValueUnquoted |
            states::AfterAttributeValueQuoted |
            states::SelfClosingStartTag |
            states::CommentStart |
            states::CommentStartDash |
            states::Comment |
            states::CommentEndDash |
            states::CommentEnd |
            states::CommentEndBang |
            states::Doctype |
            states::BeforeDoctypeName |
            states::DoctypeName |
            states::AfterDoctypeName |
            states::AfterDoctypePublicKeyword |
            states::BeforeDoctypePublicIdentifier |
            states::DoctypePublicIdentifierDoubleQuoted |
            states::DoctypePublicIdentifierSingleQuoted |
            states::AfterDoctypePublicIdentifier |
            states::BetweenDoctypePublicAndSystemIdentifiers |
            states::AfterDoctypeSystemKeyword |
            states::BeforeDoctypeSystemIdentifier |
            states::DoctypeSystemIdentifierDoubleQuoted |
            states::DoctypeSystemIdentifierSingleQuoted |
            states::AfterDoctypeSystemIdentifier |
            states::BogusDoctype |
            states::CharacterReferenceInData |
            states::CharacterReferenceInRcdata |
            states::CharacterReferenceInAttributeValue |
            states::BogusComment |
            states::MarkupDeclarationOpen |
            states::CdataSection
                => fail!("FIXME: state {:?} not implemented", self.state),
        }

        Finished

    }
}
<|endoftext|>


<commit_before>mod moduletype;
mod types;

use std::path::Path;
use std::rc::Rc;
use thiserror::Error;

use witx::{self, Id, Module};

pub use self::moduletype::ModuleType;
pub use self::types::{FuncSignature, ImportFunc};
pub use witx::{AtomType, Document, WitxError};

#[derive(Debug, Error)]
pub enum Error {
    #[error("WebAssembly validation error at offset {1}: {0}")]
    WasmValidation(&'static str, usize),
    #[error("Unsupported: {0}")]
    Unsupported(String),
    #[error("Module not found: {0}")]
    ModuleNotFound(String),
    #[error("Import not found: {module}::{field}")]
    ImportNotFound { module: String, field: String },
    #[error("Export not found: {field}")]
    ExportNotFound { field: String },
    #[error("Import type error: for {module}::{field}, expected {expected:?}, got {got:?}")]
    ImportTypeError {
        module: String,
        field: String,
        expected: FuncSignature,
        got: FuncSignature,
    },
    #[error("Export type error: for {field}, expected {expected:?}, got {got:?}")]
    ExportTypeError {
        field: String,
        expected: FuncSignature,
        got: FuncSignature,
    },
}

impl From<wasmparser::BinaryReaderError> for Error {
    fn from(e: wasmparser::BinaryReaderError) -> Error {
        Error::WasmValidation(e.message, e.offset)
    }
}

pub struct Validator {
    witx: Document,
    wasi_exe: bool,
}

impl Validator {
    pub fn new(witx: Document, wasi_exe: bool) -> Self {
        Self { witx, wasi_exe }
    }

    pub fn parse(source: &str) -> Result<Self, WitxError> {
        let witx = witx::parse(source)?;
        Ok(Self {
            witx,
            wasi_exe: false,
        })
    }

    pub fn load<P: AsRef<Path>>(source_paths: &[P]) -> Result<Self, WitxError> {
        let witx = witx::load(source_paths)?;
        Ok(Self {
            witx,
            wasi_exe: false,
        })
    }

    pub fn wasi_exe(&mut self, check: bool) {
        self.wasi_exe = check;
    }

    pub fn with_wasi_exe(mut self, check: bool) -> Self {
        self.wasi_exe(check);
        self
    }

    pub fn validate(&self, module_contents: &[u8]) -> Result<(), Error> {
        wasmparser::validate(module_contents, None)?;

        let moduletype = ModuleType::parse_wasm(module_contents)?;

        for import in moduletype.imports() {
            let func = self
                .witx_module(&import.module)?
                .func(&Id::new(&import.field))
                .ok_or_else(|| Error::ImportNotFound {
                    module: import.module.clone(),
                    field: import.field.clone(),
                })?;
            let spec_type = FuncSignature::from(func.core_type());
            if spec_type != import.ty {
                return Err(Error::ImportTypeError {
                    module: import.module,
                    field: import.field,
                    got: import.ty,
                    expected: spec_type,
                });
            }
        }

        if self.wasi_exe {
            self.check_wasi_start_func(&moduletype)?;
        }

        Ok(())
    }

    fn witx_module(&self, module: &str) -> Result<Rc<Module>, Error> {
        self.witx
            .module(&Id::new(module))
            .ok_or_else(|| Error::ModuleNotFound(module.to_string()))
    }

    fn check_wasi_start_func(&self, moduletype: &ModuleType) -> Result<(), Error> {
        let start_name = "_start";
        let expected = FuncSignature {
            args: vec![],
            ret: None,
        };
        if let Some(startfunc) = moduletype.export(start_name) {
            if startfunc != &expected {
                Err(Error::ExportTypeError {
                    field: start_name.to_string(),
                    expected,
                    got: startfunc.clone(),
                })
            } else {
                Ok(())
            }
        } else {
            Err(Error::ExportNotFound {
                field: start_name.to_string(),
            })
        }
    }
}
<commit_msg>lucet-validate: add accessor to get witx doc<commit_after>mod moduletype;
mod types;

use std::path::Path;
use std::rc::Rc;
use thiserror::Error;

use witx::{self, Id, Module};

pub use self::moduletype::ModuleType;
pub use self::types::{FuncSignature, ImportFunc};
pub use witx::{AtomType, Document, WitxError};

#[derive(Debug, Error)]
pub enum Error {
    #[error("WebAssembly validation error at offset {1}: {0}")]
    WasmValidation(&'static str, usize),
    #[error("Unsupported: {0}")]
    Unsupported(String),
    #[error("Module not found: {0}")]
    ModuleNotFound(String),
    #[error("Import not found: {module}::{field}")]
    ImportNotFound { module: String, field: String },
    #[error("Export not found: {field}")]
    ExportNotFound { field: String },
    #[error("Import type error: for {module}::{field}, expected {expected:?}, got {got:?}")]
    ImportTypeError {
        module: String,
        field: String,
        expected: FuncSignature,
        got: FuncSignature,
    },
    #[error("Export type error: for {field}, expected {expected:?}, got {got:?}")]
    ExportTypeError {
        field: String,
        expected: FuncSignature,
        got: FuncSignature,
    },
}

impl From<wasmparser::BinaryReaderError> for Error {
    fn from(e: wasmparser::BinaryReaderError) -> Error {
        Error::WasmValidation(e.message, e.offset)
    }
}

pub struct Validator {
    witx: Document,
    wasi_exe: bool,
}

impl Validator {
    pub fn new(witx: Document, wasi_exe: bool) -> Self {
        Self { witx, wasi_exe }
    }

    pub fn parse(source: &str) -> Result<Self, WitxError> {
        let witx = witx::parse(source)?;
        Ok(Self {
            witx,
            wasi_exe: false,
        })
    }

    pub fn load<P: AsRef<Path>>(source_paths: &[P]) -> Result<Self, WitxError> {
        let witx = witx::load(source_paths)?;
        Ok(Self {
            witx,
            wasi_exe: false,
        })
    }

    pub fn wasi_exe(&mut self, check: bool) {
        self.wasi_exe = check;
    }

    pub fn with_wasi_exe(mut self, check: bool) -> Self {
        self.wasi_exe(check);
        self
    }

    pub fn validate(&self, module_contents: &[u8]) -> Result<(), Error> {
        wasmparser::validate(module_contents, None)?;

        let moduletype = ModuleType::parse_wasm(module_contents)?;

        for import in moduletype.imports() {
            let func = self
                .witx_module(&import.module)?
                .func(&Id::new(&import.field))
                .ok_or_else(|| Error::ImportNotFound {
                    module: import.module.clone(),
                    field: import.field.clone(),
                })?;
            let spec_type = FuncSignature::from(func.core_type());
            if spec_type != import.ty {
                return Err(Error::ImportTypeError {
                    module: import.module,
                    field: import.field,
                    got: import.ty,
                    expected: spec_type,
                });
            }
        }

        if self.wasi_exe {
            self.check_wasi_start_func(&moduletype)?;
        }

        Ok(())
    }

    pub fn doc(&self) -> &Document {
        &self.witx
    }

    fn witx_module(&self, module: &str) -> Result<Rc<Module>, Error> {
        self.witx
            .module(&Id::new(module))
            .ok_or_else(|| Error::ModuleNotFound(module.to_string()))
    }

    fn check_wasi_start_func(&self, moduletype: &ModuleType) -> Result<(), Error> {
        let start_name = "_start";
        let expected = FuncSignature {
            args: vec![],
            ret: None,
        };
        if let Some(startfunc) = moduletype.export(start_name) {
            if startfunc != &expected {
                Err(Error::ExportTypeError {
                    field: start_name.to_string(),
                    expected,
                    got: startfunc.clone(),
                })
            } else {
                Ok(())
            }
        } else {
            Err(Error::ExportNotFound {
                field: start_name.to_string(),
            })
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

#![deny(warnings)]

extern crate build_helper;
extern crate gcc;

use std::env;
use std::path::PathBuf;
use std::process::Command;
use build_helper::{run, native_lib_boilerplate};

fn main() {
    // FIXME: This is a hack to support building targets that don't
    // support jemalloc alongside hosts that do. The jemalloc build is
    // controlled by a feature of the std crate, and if that feature
    // changes between targets, it invalidates the fingerprint of
    // std's build script (this is a cargo bug); so we must ensure
    // that the feature set used by std is the same across all
    // targets, which means we have to build the alloc_jemalloc crate
    // for targets like emscripten, even if we don't use it.
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") ||
       target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") ||
       target.contains("redox") {
        println!("cargo:rustc-cfg=dummy_jemalloc");
        return;
    }

    if target.contains("android") {
        println!("cargo:rustc-link-lib=gcc");
    } else if !target.contains("windows") && !target.contains("musl") {
        println!("cargo:rustc-link-lib=pthread");
    }

    if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
        let jemalloc = PathBuf::from(jemalloc);
        println!("cargo:rustc-link-search=native={}",
                 jemalloc.parent().unwrap().display());
        let stem = jemalloc.file_stem().unwrap().to_str().unwrap();
        let name = jemalloc.file_name().unwrap().to_str().unwrap();
        let kind = if name.ends_with(".a") {
            "static"
        } else {
            "dylib"
        };
        println!("cargo:rustc-link-lib={}={}", kind, &stem[3..]);
        return;
    }

    let link_name = if target.contains("windows") { "jemalloc" } else { "jemalloc_pic" };
    let native = match native_lib_boilerplate("jemalloc", "jemalloc", link_name, "lib") {
        Ok(native) => native,
        _ => return,
    };

    let compiler = gcc::Config::new().get_compiler();
    // only msvc returns None for ar so unwrap is okay
    let ar = build_helper::cc2ar(compiler.path(), &target).unwrap();
    let cflags = compiler.args()
        .iter()
        .map(|s| s.to_str().unwrap())
        .collect::<Vec<_>>()
        .join(" ");

    let mut cmd = Command::new("sh");
    cmd.arg(native.src_dir.join("configure")
                          .to_str()
                          .unwrap()
                          .replace("C:\\", "/c/")
                          .replace("\\", "/"))
       .current_dir(&native.out_dir)
       .env("CC", compiler.path())
       .env("EXTRA_CFLAGS", cflags.clone())
       // jemalloc generates Makefile deps using GCC's "-MM" flag. This means
       // that GCC will run the preprocessor, and only the preprocessor, over
       // jemalloc's source files. If we don't specify CPPFLAGS, then at least
       // on ARM that step fails with a "Missing implementation for 32-bit
       // atomic operations" error. This is because no "-march" flag will be
       // passed to GCC, and then GCC won't define the
       // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
       // select an atomic operation implementation.
       .env("CPPFLAGS", cflags.clone())
       .env("AR", &ar)
       .env("RANLIB", format!("{} s", ar.display()));

    if target.contains("ios") {
        cmd.arg("--disable-tls");
    } else if target.contains("android") {
        // We force android to have prefixed symbols because apparently
        // replacement of the libc allocator doesn't quite work. When this was
        // tested (unprefixed symbols), it was found that the `realpath`
        // function in libc would allocate with libc malloc (not jemalloc
        // malloc), and then the standard library would free with jemalloc free,
        // causing a segfault.
        //
        // If the test suite passes, however, without symbol prefixes then we
        // should be good to go!
        cmd.arg("--with-jemalloc-prefix=je_");
        cmd.arg("--disable-tls");
    } else if target.contains("dragonfly") || target.contains("musl") {
        cmd.arg("--with-jemalloc-prefix=je_");
    }

    if cfg!(feature = "debug-jemalloc") {
        cmd.arg("--enable-debug");
    }

    cmd.arg(format!("--host={}", build_helper::gnu_target(&target)));
    cmd.arg(format!("--build={}", build_helper::gnu_target(&host)));

    // for some reason, jemalloc configure doesn't detect this value
    // automatically for this target
    if target == "sparc64-unknown-linux-gnu" {
        cmd.arg("--with-lg-quantum=4");
    }

    run(&mut cmd);

    let mut make = Command::new(build_helper::make(&host));
    make.current_dir(&native.out_dir)
        .arg("build_lib_static");

    // These are intended for mingw32-make which we don't use
    if cfg!(windows) {
        make.env_remove("MAKEFLAGS").env_remove("MFLAGS");
    }

    // mingw make seems... buggy? unclear...
    if !host.contains("windows") {
        make.arg("-j")
            .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"));
    }

    run(&mut make);

    // The pthread_atfork symbols is used by jemalloc on android but the really
    // old android we're building on doesn't have them defined, so just make
    // sure the symbols are available.
    if target.contains("androideabi") {
        println!("cargo:rerun-if-changed=pthread_atfork_dummy.c");
        gcc::Config::new()
            .flag("-fvisibility=hidden")
            .file("pthread_atfork_dummy.c")
            .compile("libpthread_atfork_dummy.a");
    }
}
<commit_msg>Auto merge of #43648 - RalfJung:jemalloc-debug, r=alexcrichton<commit_after>// Copyright 2015 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.

#![deny(warnings)]

extern crate build_helper;
extern crate gcc;

use std::env;
use std::path::PathBuf;
use std::process::Command;
use build_helper::{run, native_lib_boilerplate};

fn main() {
    // FIXME: This is a hack to support building targets that don't
    // support jemalloc alongside hosts that do. The jemalloc build is
    // controlled by a feature of the std crate, and if that feature
    // changes between targets, it invalidates the fingerprint of
    // std's build script (this is a cargo bug); so we must ensure
    // that the feature set used by std is the same across all
    // targets, which means we have to build the alloc_jemalloc crate
    // for targets like emscripten, even if we don't use it.
    let target = env::var("TARGET").expect("TARGET was not set");
    let host = env::var("HOST").expect("HOST was not set");
    if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") ||
       target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") ||
       target.contains("redox") {
        println!("cargo:rustc-cfg=dummy_jemalloc");
        return;
    }

    if target.contains("android") {
        println!("cargo:rustc-link-lib=gcc");
    } else if !target.contains("windows") && !target.contains("musl") {
        println!("cargo:rustc-link-lib=pthread");
    }

    if let Some(jemalloc) = env::var_os("JEMALLOC_OVERRIDE") {
        let jemalloc = PathBuf::from(jemalloc);
        println!("cargo:rustc-link-search=native={}",
                 jemalloc.parent().unwrap().display());
        let stem = jemalloc.file_stem().unwrap().to_str().unwrap();
        let name = jemalloc.file_name().unwrap().to_str().unwrap();
        let kind = if name.ends_with(".a") {
            "static"
        } else {
            "dylib"
        };
        println!("cargo:rustc-link-lib={}={}", kind, &stem[3..]);
        return;
    }

    let link_name = if target.contains("windows") { "jemalloc" } else { "jemalloc_pic" };
    let native = match native_lib_boilerplate("jemalloc", "jemalloc", link_name, "lib") {
        Ok(native) => native,
        _ => return,
    };

    let compiler = gcc::Config::new().get_compiler();
    // only msvc returns None for ar so unwrap is okay
    let ar = build_helper::cc2ar(compiler.path(), &target).unwrap();
    let cflags = compiler.args()
        .iter()
        .map(|s| s.to_str().unwrap())
        .collect::<Vec<_>>()
        .join(" ");

    let mut cmd = Command::new("sh");
    cmd.arg(native.src_dir.join("configure")
                          .to_str()
                          .unwrap()
                          .replace("C:\\", "/c/")
                          .replace("\\", "/"))
       .current_dir(&native.out_dir)
       .env("CC", compiler.path())
       .env("EXTRA_CFLAGS", cflags.clone())
       // jemalloc generates Makefile deps using GCC's "-MM" flag. This means
       // that GCC will run the preprocessor, and only the preprocessor, over
       // jemalloc's source files. If we don't specify CPPFLAGS, then at least
       // on ARM that step fails with a "Missing implementation for 32-bit
       // atomic operations" error. This is because no "-march" flag will be
       // passed to GCC, and then GCC won't define the
       // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to
       // select an atomic operation implementation.
       .env("CPPFLAGS", cflags.clone())
       .env("AR", &ar)
       .env("RANLIB", format!("{} s", ar.display()));

    if target.contains("ios") {
        cmd.arg("--disable-tls");
    } else if target.contains("android") {
        // We force android to have prefixed symbols because apparently
        // replacement of the libc allocator doesn't quite work. When this was
        // tested (unprefixed symbols), it was found that the `realpath`
        // function in libc would allocate with libc malloc (not jemalloc
        // malloc), and then the standard library would free with jemalloc free,
        // causing a segfault.
        //
        // If the test suite passes, however, without symbol prefixes then we
        // should be good to go!
        cmd.arg("--with-jemalloc-prefix=je_");
        cmd.arg("--disable-tls");
    } else if target.contains("dragonfly") || target.contains("musl") {
        cmd.arg("--with-jemalloc-prefix=je_");
    }

    // FIXME: building with jemalloc assertions is currently broken.
    // See <https://github.com/rust-lang/rust/issues/44152>.
    //if cfg!(feature = "debug") {
    //    cmd.arg("--enable-debug");
    //}

    cmd.arg(format!("--host={}", build_helper::gnu_target(&target)));
    cmd.arg(format!("--build={}", build_helper::gnu_target(&host)));

    // for some reason, jemalloc configure doesn't detect this value
    // automatically for this target
    if target == "sparc64-unknown-linux-gnu" {
        cmd.arg("--with-lg-quantum=4");
    }

    run(&mut cmd);

    let mut make = Command::new(build_helper::make(&host));
    make.current_dir(&native.out_dir)
        .arg("build_lib_static");

    // These are intended for mingw32-make which we don't use
    if cfg!(windows) {
        make.env_remove("MAKEFLAGS").env_remove("MFLAGS");
    }

    // mingw make seems... buggy? unclear...
    if !host.contains("windows") {
        make.arg("-j")
            .arg(env::var("NUM_JOBS").expect("NUM_JOBS was not set"));
    }

    run(&mut make);

    // The pthread_atfork symbols is used by jemalloc on android but the really
    // old android we're building on doesn't have them defined, so just make
    // sure the symbols are available.
    if target.contains("androideabi") {
        println!("cargo:rerun-if-changed=pthread_atfork_dummy.c");
        gcc::Config::new()
            .flag("-fvisibility=hidden")
            .file("pthread_atfork_dummy.c")
            .compile("libpthread_atfork_dummy.a");
    }
}
<|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.

use sys::mutex as imp;

/// An OS-based mutual exclusion lock.
///
/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of
/// this mutex is unsafe and it is recommended to instead use the safe wrapper
/// at the top level of the crate instead of this type.
pub struct Mutex(imp::Mutex);

unsafe impl Sync for Mutex {}

impl Mutex {
    /// Creates a new mutex for use.
    ///
    /// Behavior is undefined if the mutex is moved after it is
    /// first used with any of the functions below.
    /// Also, the mutex might not be fully functional without calling
    /// `init`!  For example, on unix, the mutex is reentrant
    /// until `init` reconfigures it appropriately.
    pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) }

    /// Prepare the mutex for use.
    ///
    /// This should be called once the mutex is at a stable memory address.
    /// It must not be called concurrently with any other operation.
    #[inline]
    pub unsafe fn init(&mut self) { self.0.init() }

    /// Locks the mutex blocking the current thread until it is available.
    ///
    /// Behavior is undefined if the mutex has been moved between this and any
    /// previous function call.
    #[inline]
    pub unsafe fn raw_lock(&self) { self.0.lock() }

    /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
    /// will be unlocked.
    #[inline]
    pub unsafe fn lock(&self) -> MutexGuard {
        self.raw_lock();
        MutexGuard(&self.0)
    }

    /// Attempts to lock the mutex without blocking, returning whether it was
    /// successfully acquired or not.
    ///
    /// Behavior is undefined if the mutex has been moved between this and any
    /// previous function call.
    #[inline]
    pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() }

    /// Unlocks the mutex.
    ///
    /// Behavior is undefined if the current thread does not actually hold the
    /// mutex.
    ///
    /// Consider switching from the pair of raw_lock() and raw_unlock() to
    /// lock() whenever possible.
    #[inline]
    pub unsafe fn raw_unlock(&self) { self.0.unlock() }

    /// Deallocates all resources associated with this mutex.
    ///
    /// Behavior is undefined if there are current or will be future users of
    /// this mutex.
    #[inline]
    pub unsafe fn destroy(&self) { self.0.destroy() }
}

// not meant to be exported to the outside world, just the containing module
pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 }

#[must_use]
/// A simple RAII utility for the above Mutex without the poisoning semantics.
pub struct MutexGuard<'a>(&'a imp::Mutex);

impl<'a> Drop for MutexGuard<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe { self.0.unlock(); }
    }
}
<commit_msg>I think we have to strengthen Mutex::init UB<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.

use sys::mutex as imp;

/// An OS-based mutual exclusion lock.
///
/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of
/// this mutex is unsafe and it is recommended to instead use the safe wrapper
/// at the top level of the crate instead of this type.
pub struct Mutex(imp::Mutex);

unsafe impl Sync for Mutex {}

impl Mutex {
    /// Creates a new mutex for use.
    ///
    /// Behavior is undefined if the mutex is moved after it is
    /// first used with any of the functions below.
    /// Also, the mutex might not be fully functional without calling
    /// `init`!  For example, on unix, the mutex is reentrant
    /// until `init` reconfigures it appropriately.
    pub const fn new() -> Mutex { Mutex(imp::Mutex::new()) }

    /// Prepare the mutex for use.
    ///
    /// This should be called once the mutex is at a stable memory address.
    /// Behavior is undefined unless this is called before any other operation.
    #[inline]
    pub unsafe fn init(&mut self) { self.0.init() }

    /// Locks the mutex blocking the current thread until it is available.
    ///
    /// Behavior is undefined if the mutex has been moved between this and any
    /// previous function call.
    #[inline]
    pub unsafe fn raw_lock(&self) { self.0.lock() }

    /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
    /// will be unlocked.
    #[inline]
    pub unsafe fn lock(&self) -> MutexGuard {
        self.raw_lock();
        MutexGuard(&self.0)
    }

    /// Attempts to lock the mutex without blocking, returning whether it was
    /// successfully acquired or not.
    ///
    /// Behavior is undefined if the mutex has been moved between this and any
    /// previous function call.
    #[inline]
    pub unsafe fn try_lock(&self) -> bool { self.0.try_lock() }

    /// Unlocks the mutex.
    ///
    /// Behavior is undefined if the current thread does not actually hold the
    /// mutex.
    ///
    /// Consider switching from the pair of raw_lock() and raw_unlock() to
    /// lock() whenever possible.
    #[inline]
    pub unsafe fn raw_unlock(&self) { self.0.unlock() }

    /// Deallocates all resources associated with this mutex.
    ///
    /// Behavior is undefined if there are current or will be future users of
    /// this mutex.
    #[inline]
    pub unsafe fn destroy(&self) { self.0.destroy() }
}

// not meant to be exported to the outside world, just the containing module
pub fn raw(mutex: &Mutex) -> &imp::Mutex { &mutex.0 }

#[must_use]
/// A simple RAII utility for the above Mutex without the poisoning semantics.
pub struct MutexGuard<'a>(&'a imp::Mutex);

impl<'a> Drop for MutexGuard<'a> {
    #[inline]
    fn drop(&mut self) {
        unsafe { self.0.unlock(); }
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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.

//! Library providing a GUID (Globally Unique Identifier) type. The
//! format is described in Appendix A of the UEFI
//! Specification. This format of GUID is also used in Microsoft
//! Windows.
//!
//! # Features
//!
//! No features are enabled by default.
//!
//! * `bytemuck`: Implements bytemuck's `Pod` and `Zeroable` traits for `Guid`.
//! * `serde`: Implements serde's `Serialize` and `Deserialize` traits for `Guid`.
//! * `std`: Provides `std::error::Error` implementation for the error type.
//!
//! # Examples
//!
//! Construct a GUID at compile time with the `guid!` macro:
//!
//! ```
//! use uguid::guid;
//!
//! let guid = guid!("01234567-89ab-cdef-0123-456789abcdef");
//! ```
//!
//! Parse a GUID at runtime from a string:
//!
//! ```
//! use uguid::Guid;
//!
//! let guid: Guid = "01234567-89ab-cdef-0123-456789abcdef".parse().unwrap();
//! ```
//!
//! Construct a GUID from its components or a byte array:
//!
//! ```
//! use uguid::Guid;
//!
//! let guid1 = Guid::new(
//!     0x01234567_u32.to_le_bytes(),
//!     0x89ab_u16.to_le_bytes(),
//!     0xcdef_u16.to_le_bytes(),
//!     0x01,
//!     0x23,
//!     [0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
//! );
//! let guid2 = Guid::from_bytes([
//!     0x67, 0x45, 0x23, 0x01, 0xab, 0x89, 0xef, 0xcd, 0x01, 0x23, 0x45, 0x67,
//!     0x89, 0xab, 0xcd, 0xef,
//! ]);
//! assert_eq!(guid1, guid2);
//! ```
//!
//! Convert to a string or a byte array:
//!
//! ```
//! use uguid::guid;
//!
//! let guid = guid!("01234567-89ab-cdef-0123-456789abcdef");
//! assert_eq!(guid.to_string(), "01234567-89ab-cdef-0123-456789abcdef");
//! assert_eq!(
//!     guid.to_bytes(),
//!     [
//!         0x67, 0x45, 0x23, 0x01, 0xab, 0x89, 0xef, 0xcd, 0x01, 0x23, 0x45,
//!         0x67, 0x89, 0xab, 0xcd, 0xef
//!     ]
//! );
//! ```

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unreachable_pub)]
#![warn(unsafe_code)]
#![warn(clippy::pedantic)]
#![warn(clippy::as_conversions)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::module_name_repetitions)]

/// Macro replacement for the `?` operator, which cannot be used in
/// const functions.
macro_rules! mtry {
    ($expr:expr $(,)?) => {
        match $expr {
            Ok(val) => val,
            Err(err) => {
                return Err(err);
            }
        }
    };
}

pub mod aligned;
mod error;
mod unaligned;
mod util;

pub use error::GuidFromStrError;
pub use unaligned::Guid;

#[cfg(feature = "std")]
impl std::error::Error for GuidFromStrError {}

/// Create an unaligned [`Guid`] from a string at compile time.
///
/// # Examples
///
/// ```
/// use uguid::{guid, Guid};
/// assert_eq!(
///     guid!("01234567-89ab-cdef-0123-456789abcdef"),
///     Guid::new(
///         0x01234567_u32.to_le_bytes(),
///         0x89ab_u16.to_le_bytes(),
///         0xcdef_u16.to_le_bytes(),
///         0x01,
///         0x23,
///         [0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
///     )
/// );
/// ```
#[macro_export]
macro_rules! guid {
    ($s:literal) => {
        match $crate::Guid::try_parse($s) {
            Ok(g) => g,
            Err(_) => panic!("invalid GUID string"),
        }
    };
}

/// Create an [`aligned::Guid`] from a string at compile time.
///
/// # Examples
///
/// ```
/// use uguid::aligned::Guid;
/// use uguid::aligned_guid;
/// assert_eq!(
///     aligned_guid!("01234567-89ab-cdef-0123-456789abcdef"),
///     Guid::new(
///         0x01234567_u32.to_le_bytes(),
///         0x89ab_u16.to_le_bytes(),
///         0xcdef_u16.to_le_bytes(),
///         0x01,
///         0x23,
///         [0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
///     )
/// );
/// ```
#[macro_export]
macro_rules! aligned_guid {
    ($s:literal) => {
        match $crate::aligned::Guid::try_parse($s) {
            Ok(g) => g,
            Err(_) => panic!("invalid GUID string"),
        }
    };
}
<commit_msg>uguid: Add AlignedGuid<commit_after>// Copyright 2022 Google LLC
//
// 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.

//! Library providing a GUID (Globally Unique Identifier) type. The
//! format is described in Appendix A of the UEFI
//! Specification. This format of GUID is also used in Microsoft
//! Windows.
//!
//! # Features
//!
//! No features are enabled by default.
//!
//! * `bytemuck`: Implements bytemuck's `Pod` and `Zeroable` traits for `Guid`.
//! * `serde`: Implements serde's `Serialize` and `Deserialize` traits for `Guid`.
//! * `std`: Provides `std::error::Error` implementation for the error type.
//!
//! # Examples
//!
//! Construct a GUID at compile time with the `guid!` macro:
//!
//! ```
//! use uguid::guid;
//!
//! let guid = guid!("01234567-89ab-cdef-0123-456789abcdef");
//! ```
//!
//! Parse a GUID at runtime from a string:
//!
//! ```
//! use uguid::Guid;
//!
//! let guid: Guid = "01234567-89ab-cdef-0123-456789abcdef".parse().unwrap();
//! ```
//!
//! Construct a GUID from its components or a byte array:
//!
//! ```
//! use uguid::Guid;
//!
//! let guid1 = Guid::new(
//!     0x01234567_u32.to_le_bytes(),
//!     0x89ab_u16.to_le_bytes(),
//!     0xcdef_u16.to_le_bytes(),
//!     0x01,
//!     0x23,
//!     [0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
//! );
//! let guid2 = Guid::from_bytes([
//!     0x67, 0x45, 0x23, 0x01, 0xab, 0x89, 0xef, 0xcd, 0x01, 0x23, 0x45, 0x67,
//!     0x89, 0xab, 0xcd, 0xef,
//! ]);
//! assert_eq!(guid1, guid2);
//! ```
//!
//! Convert to a string or a byte array:
//!
//! ```
//! use uguid::guid;
//!
//! let guid = guid!("01234567-89ab-cdef-0123-456789abcdef");
//! assert_eq!(guid.to_string(), "01234567-89ab-cdef-0123-456789abcdef");
//! assert_eq!(
//!     guid.to_bytes(),
//!     [
//!         0x67, 0x45, 0x23, 0x01, 0xab, 0x89, 0xef, 0xcd, 0x01, 0x23, 0x45,
//!         0x67, 0x89, 0xab, 0xcd, 0xef
//!     ]
//! );
//! ```

#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unreachable_pub)]
#![warn(unsafe_code)]
#![warn(clippy::pedantic)]
#![warn(clippy::as_conversions)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::module_name_repetitions)]

/// Macro replacement for the `?` operator, which cannot be used in
/// const functions.
macro_rules! mtry {
    ($expr:expr $(,)?) => {
        match $expr {
            Ok(val) => val,
            Err(err) => {
                return Err(err);
            }
        }
    };
}

mod aligned;
mod error;
mod unaligned;
mod util;

pub use aligned::Guid as AlignedGuid;
pub use error::GuidFromStrError;
pub use unaligned::Guid;

#[cfg(feature = "std")]
impl std::error::Error for GuidFromStrError {}

/// Create an unaligned [`Guid`] from a string at compile time.
///
/// # Examples
///
/// ```
/// use uguid::{guid, Guid};
/// assert_eq!(
///     guid!("01234567-89ab-cdef-0123-456789abcdef"),
///     Guid::new(
///         0x01234567_u32.to_le_bytes(),
///         0x89ab_u16.to_le_bytes(),
///         0xcdef_u16.to_le_bytes(),
///         0x01,
///         0x23,
///         [0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
///     )
/// );
/// ```
#[macro_export]
macro_rules! guid {
    ($s:literal) => {
        match $crate::Guid::try_parse($s) {
            Ok(g) => g,
            Err(_) => panic!("invalid GUID string"),
        }
    };
}

/// Create an [`AlignedGuid`] from a string at compile time.
///
/// # Examples
///
/// ```
/// use uguid::{AlignedGuid, aligned_guid};
/// assert_eq!(
///     aligned_guid!("01234567-89ab-cdef-0123-456789abcdef"),
///     AlignedGuid::new(
///         0x01234567_u32.to_le_bytes(),
///         0x89ab_u16.to_le_bytes(),
///         0xcdef_u16.to_le_bytes(),
///         0x01,
///         0x23,
///         [0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
///     )
/// );
/// ```
#[macro_export]
macro_rules! aligned_guid {
    ($s:literal) => {
        match $crate::AlignedGuid::try_parse($s) {
            Ok(g) => g,
            Err(_) => panic!("invalid GUID string"),
        }
    };
}
<|endoftext|>


<commit_before>extern crate easystring;

#[cfg(test)]
mod index {
    use std::ffi::{CStr, CString, OsStr, OsString};
    use std::path::{Path, PathBuf};
    use easystring::{Content, ToContent};

    #[test]
    fn slice() {
        let content = Content::from("abcde");
        assert_eq!(content, "abcde");
    }
}

#[cfg(test)]
mod compare {
    use std::ffi::{CStr, CString, OsStr, OsString};
    use std::path::{Path, PathBuf};
    use easystring::{Content, ToContent};

    #[test]
    fn with_str() {
        let conent = Content::from("12345");
        assert_eq!(conent, "12345");
    }

    #[test]
    fn with_string() {
        let conent = Content::from("12345");
        let string = String::from("12345");
        assert_eq!(conent, string);
    }

    #[test]
    fn with_osstr() {
        let conent = Content::from("12345");
        let osstr = OsStr::new("12345");
        assert_eq!(conent, osstr);
    }

    #[test]
    fn with_osstring() {
        let content = Content::from("12345");
        let osstring = OsString::from("12345");
        assert_eq!(content, osstring);
    }

    #[test]
    fn with_cstr() {
        let content = Content::from("12345");
        let cstring = CString::new(b"12345".to_vec()).unwrap();
        let cstr = cstring.as_ref();
        assert_eq!(content, cstr);
    }

    #[test]
    fn with_cstring() {
        let content = Content::from("12345");
        let cstring = CString::new(b"12345".to_vec()).unwrap();
        assert_eq!(content, cstring);
    }

    #[test]
    fn with_path() {
        let conent = Content::from("12345");
        let path = Path::new("12345");
        assert_eq!(conent, path);
    }

    #[test]
    fn with_pathbuf() {
        let conent = Content::from("12345");
        let pathbuf = PathBuf::from("12345");
        assert_eq!(conent, pathbuf);
    }
}
<commit_msg>Reformat tests<commit_after>extern crate easystring;

#[cfg(test)]
mod content {
    mod index {
        use std::ffi::{CStr, CString, OsStr, OsString};
        use std::path::{Path, PathBuf};
        use easystring::{Content, ToContent};

        #[test]
        fn slice() {
            let content = Content::from("abcde");
            assert_eq!(content, "abcde");
        }
    }

    mod compare {
        use std::ffi::{CStr, CString, OsStr, OsString};
        use std::path::{Path, PathBuf};
        use easystring::{Content, ToContent};

        #[test]
        fn with_str() {
            let conent = Content::from("12345");
            assert_eq!(conent, "12345");
        }

        #[test]
        fn with_string() {
            let conent = Content::from("12345");
            let string = String::from("12345");
            assert_eq!(conent, string);
        }

        #[test]
        fn with_osstr() {
            let conent = Content::from("12345");
            let osstr = OsStr::new("12345");
            assert_eq!(conent, osstr);
        }

        #[test]
        fn with_osstring() {
            let content = Content::from("12345");
            let osstring = OsString::from("12345");
            assert_eq!(content, osstring);
        }

        #[test]
        fn with_cstr() {
            let content = Content::from("12345");
            let cstring = CString::new(b"12345".to_vec()).unwrap();
            let cstr = cstring.as_ref();
            assert_eq!(content, cstr);
        }

        #[test]
        fn with_cstring() {
            let content = Content::from("12345");
            let cstring = CString::new(b"12345".to_vec()).unwrap();
            assert_eq!(content, cstring);
        }

        #[test]
        fn with_path() {
            let conent = Content::from("12345");
            let path = Path::new("12345");
            assert_eq!(conent, path);
        }

        #[test]
        fn with_pathbuf() {
            let conent = Content::from("12345");
            let pathbuf = PathBuf::from("12345");
            assert_eq!(conent, pathbuf);
        }
    }
}
<|endoftext|>


<commit_before>extern crate assert_cli;

#[cfg(feature="integration_tests")]
mod tests {
    use assert_cli::Assert;

    #[test]
    fn kitchen_sink() {
        // make sure we're setup and back to no applied migrations
        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["setup"])
            .unwrap();
        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["apply", "-ad"])
            .execute().is_ok();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["apply", "-ad"])
            .fails()
            .stderr().contains("MigrationComplete: No un-applied `Down` migrations found")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["list"])
            .stdout().contains("Current Migration Status:")
            .stdout().contains("[ ] 20170812145327_initial")
            .stdout().contains("[ ] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["apply", "-a"])
            .stdout().contains("Applying[Up]:")
            .stdout().contains("Current Migration Status:")
            .stdout().contains("[✓] 20170812145327_initial")
            .stdout().contains("[✓] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["list"])
            .stdout().contains("Current Migration Status:")
            .stdout().contains("[✓] 20170812145327_initial")
            .stdout().contains("[✓] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["redo"])
            .stdout().contains("Applying[Down]:")
            .stdout().contains("Current Migration Status:")
            .stdout().contains("[ ] 20171126194042_second")
            .stdout().contains("Applying[Up]:")
            .stdout().contains("Current Migration Status:")
            .stdout().contains("[✓] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["redo", "--all"])
            .stdout().contains("Applying[Down]:")
            .stdout().contains("Current Migration Status:")
            .stdout().contains("[ ] 20170812145327_initial")
            .stdout().contains("[ ] 20171126194042_second")
            .stdout().contains("Applying[Up]:")
            .stdout().contains("Current Migration Status:")
            .stdout().contains("[✓] 20170812145327_initial")
            .stdout().contains("[✓] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["apply", "-ad"])
            .execute().is_ok();
    }
}

<commit_msg>fix integration test warnings<commit_after>extern crate assert_cli;

#[cfg(feature = "integration_tests")]
mod tests {
    use assert_cli::Assert;

    #[test]
    fn kitchen_sink() {
        // make sure we're setup and back to no applied migrations
        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["setup"])
            .unwrap();
        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["apply", "-ad"])
            .execute()
            .ok();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["apply", "-ad"])
            .fails()
            .stderr()
            .contains("MigrationComplete: No un-applied `Down` migrations found")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["list"])
            .stdout()
            .contains("Current Migration Status:")
            .stdout()
            .contains("[ ] 20170812145327_initial")
            .stdout()
            .contains("[ ] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["apply", "-a"])
            .stdout()
            .contains("Applying[Up]:")
            .stdout()
            .contains("Current Migration Status:")
            .stdout()
            .contains("[✓] 20170812145327_initial")
            .stdout()
            .contains("[✓] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["list"])
            .stdout()
            .contains("Current Migration Status:")
            .stdout()
            .contains("[✓] 20170812145327_initial")
            .stdout()
            .contains("[✓] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["redo"])
            .stdout()
            .contains("Applying[Down]:")
            .stdout()
            .contains("Current Migration Status:")
            .stdout()
            .contains("[ ] 20171126194042_second")
            .stdout()
            .contains("Applying[Up]:")
            .stdout()
            .contains("Current Migration Status:")
            .stdout()
            .contains("[✓] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["redo", "--all"])
            .stdout()
            .contains("Applying[Down]:")
            .stdout()
            .contains("Current Migration Status:")
            .stdout()
            .contains("[ ] 20170812145327_initial")
            .stdout()
            .contains("[ ] 20171126194042_second")
            .stdout()
            .contains("Applying[Up]:")
            .stdout()
            .contains("Current Migration Status:")
            .stdout()
            .contains("[✓] 20170812145327_initial")
            .stdout()
            .contains("[✓] 20171126194042_second")
            .unwrap();

        Assert::command(&["cargo", "run", "--features", "sqlite", "--"])
            .with_args(&["apply", "-ad"])
            .execute()
            .ok();
    }
}
<|endoftext|>


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

use super::{
    request::{JsonRpcRequest, MethodRequest},
    response::{MethodResponse, Response},
    state::StateManager,
    validate, validate_batch, BatchResponse, USER_AGENT,
};
use crate::{
    error::WaitForTransactionError,
    views::{
        AccountStateWithProofView, AccountView, CurrencyInfoView, EventView, MetadataView,
        StateProofView, TransactionView,
    },
    Error, Result, Retry, State,
};
use diem_crypto::{hash::CryptoHash, HashValue};
use diem_types::{
    account_address::AccountAddress,
    transaction::{SignedTransaction, Transaction},
};
use serde::{de::DeserializeOwned, Serialize};
use std::time::Duration;

// In order to avoid needing to publish the proxy crate to crates.io we simply include the small
// library in inline by making it a module instead of a dependency. 'src/proxy.rs' is a symlink to
// '../../../common/proxy/src/lib.rs'
#[path = "proxy.rs"]
mod proxy;

const REQUEST_TIMEOUT: u64 = 10_000;

#[derive(Clone, Debug)]
pub struct BlockingClient {
    url: String,
    state: StateManager,
    retry: Retry,
}

impl BlockingClient {
    pub fn new<T: Into<String>>(url: T) -> Self {
        Self {
            url: url.into(),
            state: StateManager::new(),
            retry: Retry::default(),
        }
    }

    pub fn last_known_state(&self) -> Option<State> {
        self.state.last_known_state()
    }

    pub fn wait_for_signed_transaction(
        &self,
        txn: &SignedTransaction,
        timeout: Option<Duration>,
        delay: Option<Duration>,
    ) -> Result<Response<TransactionView>, WaitForTransactionError> {
        let response = self.wait_for_transaction(
            txn.sender(),
            txn.sequence_number(),
            txn.expiration_timestamp_secs(),
            Transaction::UserTransaction(txn.clone()).hash(),
            timeout,
            delay,
        )?;

        if !response.inner().vm_status.is_executed() {
            return Err(WaitForTransactionError::TransactionExecutionFailed(
                response.into_inner(),
            ));
        }

        Ok(response)
    }

    pub fn wait_for_transaction(
        &self,
        address: AccountAddress,
        seq: u64,
        expiration_time_secs: u64,
        txn_hash: HashValue,
        timeout: Option<Duration>,
        delay: Option<Duration>,
    ) -> Result<Response<TransactionView>, WaitForTransactionError> {
        const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
        const DEFAULT_DELAY: Duration = Duration::from_millis(50);

        let start = std::time::Instant::now();
        while start.elapsed() < timeout.unwrap_or(DEFAULT_TIMEOUT) {
            let txn_resp = self
                .get_account_transaction(address, seq, true)
                .map_err(WaitForTransactionError::GetTransactionError)?;
            if let (Some(txn), state) = txn_resp.into_parts() {
                if txn.hash != txn_hash {
                    return Err(WaitForTransactionError::TransactionHashMismatchError(txn));
                }

                return Ok(Response::new(txn, state));
            }

            if let Some(state) = self.last_known_state() {
                if expiration_time_secs <= state.timestamp_usecs / 1_000_000 {
                    return Err(WaitForTransactionError::TransactionExpired);
                }
            }
            std::thread::sleep(delay.unwrap_or(DEFAULT_DELAY));
        }

        Err(WaitForTransactionError::Timeout)
    }

    pub fn batch(
        &self,
        requests: Vec<MethodRequest>,
    ) -> Result<Vec<Result<Response<MethodResponse>>>> {
        self.send_batch(requests)
    }

    pub fn submit(&self, txn: &SignedTransaction) -> Result<Response<()>> {
        self.send(MethodRequest::submit(txn).map_err(Error::request)?)
    }

    pub fn get_metadata_by_version(&self, version: u64) -> Result<Response<MetadataView>> {
        self.send(MethodRequest::get_metadata_by_version(version))
    }

    pub fn get_metadata(&self) -> Result<Response<MetadataView>> {
        self.send(MethodRequest::get_metadata())
    }

    pub fn get_account(&self, address: AccountAddress) -> Result<Response<Option<AccountView>>> {
        self.send(MethodRequest::get_account(address))
    }

    pub fn get_transactions(
        &self,
        start_seq: u64,
        limit: u64,
        include_events: bool,
    ) -> Result<Response<Vec<TransactionView>>> {
        self.send(MethodRequest::get_transactions(
            start_seq,
            limit,
            include_events,
        ))
    }

    pub fn get_account_transaction(
        &self,
        address: AccountAddress,
        seq: u64,
        include_events: bool,
    ) -> Result<Response<Option<TransactionView>>> {
        self.send(MethodRequest::get_account_transaction(
            address,
            seq,
            include_events,
        ))
    }

    pub fn get_account_transactions(
        &self,
        address: AccountAddress,
        start_seq: u64,
        limit: u64,
        include_events: bool,
    ) -> Result<Response<Vec<TransactionView>>> {
        self.send(MethodRequest::get_account_transactions(
            address,
            start_seq,
            limit,
            include_events,
        ))
    }

    pub fn get_events(
        &self,
        key: &str,
        start_seq: u64,
        limit: u64,
    ) -> Result<Response<Vec<EventView>>> {
        self.send(MethodRequest::get_events(key, start_seq, limit))
    }

    pub fn get_currencies(&self) -> Result<Response<Vec<CurrencyInfoView>>> {
        self.send(MethodRequest::get_currencies())
    }

    pub fn get_network_status(&self) -> Result<Response<u64>> {
        self.send(MethodRequest::get_network_status())
    }

    //
    // Experimental APIs
    //

    pub fn get_state_proof(&self, from_version: u64) -> Result<Response<StateProofView>> {
        self.send(MethodRequest::get_state_proof(from_version))
    }

    pub fn get_account_state_with_proof(
        &self,
        address: AccountAddress,
        from_version: Option<u64>,
        to_version: Option<u64>,
    ) -> Result<Response<AccountStateWithProofView>> {
        self.send(MethodRequest::get_account_state_with_proof(
            address,
            from_version,
            to_version,
        ))
    }

    pub fn get_transactions_with_proofs(
        &self,
        start_version: u64,
        limit: u64,
    ) -> Result<Response<()>> {
        self.send(MethodRequest::get_transactions_with_proofs(
            start_version,
            limit,
        ))
    }

    pub fn get_events_with_proofs(
        &self,
        key: &str,
        start_seq: u64,
        limit: u64,
    ) -> Result<Response<()>> {
        self.send(MethodRequest::get_events_with_proofs(key, start_seq, limit))
    }

    //
    // Private Helpers
    //

    fn send<T: DeserializeOwned>(&self, request: MethodRequest) -> Result<Response<T>> {
        let request = JsonRpcRequest::new(request);
        self.retry.retry(|| {
            let resp: diem_json_rpc_types::response::JsonRpcResponse = self.send_impl(&request)?;

            let (id, state, result) = validate(&self.state, &resp)?;

            if request.id() != id {
                return Err(Error::rpc_response("invalid response id"));
            }

            let inner = serde_json::from_value(result).map_err(Error::decode)?;
            Ok(Response::new(inner, state))
        })
    }

    fn send_batch(
        &self,
        requests: Vec<MethodRequest>,
    ) -> Result<Vec<Result<Response<MethodResponse>>>> {
        let request: Vec<JsonRpcRequest> = requests.into_iter().map(JsonRpcRequest::new).collect();
        let resp: BatchResponse = self.send_impl(&request)?;

        let resp = resp.success()?;

        validate_batch(&self.state, &request, resp)
    }

    // Executes the specified request method using the given parameters by contacting the JSON RPC
    // server. If the 'http_proxy' or 'https_proxy' environment variable is set, enable the proxy.
    fn send_impl<S: Serialize, T: DeserializeOwned>(&self, payload: &S) -> Result<T> {
        let mut request = ureq::post(&self.url)
            .timeout_connect(REQUEST_TIMEOUT)
            .set("User-Agent", USER_AGENT)
            .build();

        let proxy = proxy::Proxy::new();
        let host = request.get_host().expect("unable to get the host");
        let scheme = request
            .get_scheme()
            .expect("Unable to get the scheme from the host");
        let proxy_url = match scheme.as_str() {
            "http" => proxy.http(&host),
            "https" => proxy.https(&host),
            _ => None,
        };
        if let Some(proxy_url) = proxy_url {
            request.set_proxy(ureq::Proxy::new(proxy_url).expect("Unable to parse proxy_url"));
        }

        let resp = request.send_json(serde_json::json!(payload));

        if resp.synthetic() {
            let e = resp.into_synthetic_error().unwrap();
            let error = match &e {
                ureq::Error::BadUrl(_)
                | ureq::Error::UnknownScheme(_)
                | ureq::Error::DnsFailed(_)
                | ureq::Error::BadHeader
                | ureq::Error::BadProxy
                | ureq::Error::BadProxyCreds
                | ureq::Error::ProxyConnect
                | ureq::Error::InvalidProxyCreds
                | ureq::Error::ConnectionFailed(_)
                | ureq::Error::TlsError(_) => Error::request(e),
                ureq::Error::Io(io_error) => {
                    if let std::io::ErrorKind::TimedOut = io_error.kind() {
                        Error::timeout(e)
                    } else {
                        Error::unknown(e)
                    }
                }
                _ => Error::unknown(e),
            };

            return Err(error);
        }

        if resp.status() != 200 {
            return Err(Error::status(resp.status()));
        }

        resp.into_json_deserialize().map_err(Error::decode)
    }
}
<commit_msg>[sdk] use correct response types in experimental proof API's<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use super::{
    request::{JsonRpcRequest, MethodRequest},
    response::{MethodResponse, Response},
    state::StateManager,
    validate, validate_batch, BatchResponse, USER_AGENT,
};
use crate::{
    error::WaitForTransactionError,
    views::{
        AccountStateWithProofView, AccountView, CurrencyInfoView, EventView, EventWithProofView,
        MetadataView, StateProofView, TransactionView, TransactionsWithProofsView,
    },
    Error, Result, Retry, State,
};
use diem_crypto::{hash::CryptoHash, HashValue};
use diem_types::{
    account_address::AccountAddress,
    transaction::{SignedTransaction, Transaction},
};
use serde::{de::DeserializeOwned, Serialize};
use std::time::Duration;

// In order to avoid needing to publish the proxy crate to crates.io we simply include the small
// library in inline by making it a module instead of a dependency. 'src/proxy.rs' is a symlink to
// '../../../common/proxy/src/lib.rs'
#[path = "proxy.rs"]
mod proxy;

const REQUEST_TIMEOUT: u64 = 10_000;

#[derive(Clone, Debug)]
pub struct BlockingClient {
    url: String,
    state: StateManager,
    retry: Retry,
}

impl BlockingClient {
    pub fn new<T: Into<String>>(url: T) -> Self {
        Self {
            url: url.into(),
            state: StateManager::new(),
            retry: Retry::default(),
        }
    }

    pub fn last_known_state(&self) -> Option<State> {
        self.state.last_known_state()
    }

    pub fn wait_for_signed_transaction(
        &self,
        txn: &SignedTransaction,
        timeout: Option<Duration>,
        delay: Option<Duration>,
    ) -> Result<Response<TransactionView>, WaitForTransactionError> {
        let response = self.wait_for_transaction(
            txn.sender(),
            txn.sequence_number(),
            txn.expiration_timestamp_secs(),
            Transaction::UserTransaction(txn.clone()).hash(),
            timeout,
            delay,
        )?;

        if !response.inner().vm_status.is_executed() {
            return Err(WaitForTransactionError::TransactionExecutionFailed(
                response.into_inner(),
            ));
        }

        Ok(response)
    }

    pub fn wait_for_transaction(
        &self,
        address: AccountAddress,
        seq: u64,
        expiration_time_secs: u64,
        txn_hash: HashValue,
        timeout: Option<Duration>,
        delay: Option<Duration>,
    ) -> Result<Response<TransactionView>, WaitForTransactionError> {
        const DEFAULT_TIMEOUT: Duration = Duration::from_secs(5);
        const DEFAULT_DELAY: Duration = Duration::from_millis(50);

        let start = std::time::Instant::now();
        while start.elapsed() < timeout.unwrap_or(DEFAULT_TIMEOUT) {
            let txn_resp = self
                .get_account_transaction(address, seq, true)
                .map_err(WaitForTransactionError::GetTransactionError)?;
            if let (Some(txn), state) = txn_resp.into_parts() {
                if txn.hash != txn_hash {
                    return Err(WaitForTransactionError::TransactionHashMismatchError(txn));
                }

                return Ok(Response::new(txn, state));
            }

            if let Some(state) = self.last_known_state() {
                if expiration_time_secs <= state.timestamp_usecs / 1_000_000 {
                    return Err(WaitForTransactionError::TransactionExpired);
                }
            }
            std::thread::sleep(delay.unwrap_or(DEFAULT_DELAY));
        }

        Err(WaitForTransactionError::Timeout)
    }

    pub fn batch(
        &self,
        requests: Vec<MethodRequest>,
    ) -> Result<Vec<Result<Response<MethodResponse>>>> {
        self.send_batch(requests)
    }

    pub fn submit(&self, txn: &SignedTransaction) -> Result<Response<()>> {
        self.send(MethodRequest::submit(txn).map_err(Error::request)?)
    }

    pub fn get_metadata_by_version(&self, version: u64) -> Result<Response<MetadataView>> {
        self.send(MethodRequest::get_metadata_by_version(version))
    }

    pub fn get_metadata(&self) -> Result<Response<MetadataView>> {
        self.send(MethodRequest::get_metadata())
    }

    pub fn get_account(&self, address: AccountAddress) -> Result<Response<Option<AccountView>>> {
        self.send(MethodRequest::get_account(address))
    }

    pub fn get_transactions(
        &self,
        start_seq: u64,
        limit: u64,
        include_events: bool,
    ) -> Result<Response<Vec<TransactionView>>> {
        self.send(MethodRequest::get_transactions(
            start_seq,
            limit,
            include_events,
        ))
    }

    pub fn get_account_transaction(
        &self,
        address: AccountAddress,
        seq: u64,
        include_events: bool,
    ) -> Result<Response<Option<TransactionView>>> {
        self.send(MethodRequest::get_account_transaction(
            address,
            seq,
            include_events,
        ))
    }

    pub fn get_account_transactions(
        &self,
        address: AccountAddress,
        start_seq: u64,
        limit: u64,
        include_events: bool,
    ) -> Result<Response<Vec<TransactionView>>> {
        self.send(MethodRequest::get_account_transactions(
            address,
            start_seq,
            limit,
            include_events,
        ))
    }

    pub fn get_events(
        &self,
        key: &str,
        start_seq: u64,
        limit: u64,
    ) -> Result<Response<Vec<EventView>>> {
        self.send(MethodRequest::get_events(key, start_seq, limit))
    }

    pub fn get_currencies(&self) -> Result<Response<Vec<CurrencyInfoView>>> {
        self.send(MethodRequest::get_currencies())
    }

    pub fn get_network_status(&self) -> Result<Response<u64>> {
        self.send(MethodRequest::get_network_status())
    }

    //
    // Experimental APIs
    //

    pub fn get_state_proof(&self, from_version: u64) -> Result<Response<StateProofView>> {
        self.send(MethodRequest::get_state_proof(from_version))
    }

    pub fn get_account_state_with_proof(
        &self,
        address: AccountAddress,
        from_version: Option<u64>,
        to_version: Option<u64>,
    ) -> Result<Response<AccountStateWithProofView>> {
        self.send(MethodRequest::get_account_state_with_proof(
            address,
            from_version,
            to_version,
        ))
    }

    pub fn get_transactions_with_proofs(
        &self,
        start_version: u64,
        limit: u64,
    ) -> Result<Response<Option<TransactionsWithProofsView>>> {
        self.send(MethodRequest::get_transactions_with_proofs(
            start_version,
            limit,
        ))
    }

    pub fn get_events_with_proofs(
        &self,
        key: &str,
        start_seq: u64,
        limit: u64,
    ) -> Result<Response<Vec<EventWithProofView>>> {
        self.send(MethodRequest::get_events_with_proofs(key, start_seq, limit))
    }

    //
    // Private Helpers
    //

    fn send<T: DeserializeOwned>(&self, request: MethodRequest) -> Result<Response<T>> {
        let request = JsonRpcRequest::new(request);
        self.retry.retry(|| {
            let resp: diem_json_rpc_types::response::JsonRpcResponse = self.send_impl(&request)?;

            let (id, state, result) = validate(&self.state, &resp)?;

            if request.id() != id {
                return Err(Error::rpc_response("invalid response id"));
            }

            let inner = serde_json::from_value(result).map_err(Error::decode)?;
            Ok(Response::new(inner, state))
        })
    }

    fn send_batch(
        &self,
        requests: Vec<MethodRequest>,
    ) -> Result<Vec<Result<Response<MethodResponse>>>> {
        let request: Vec<JsonRpcRequest> = requests.into_iter().map(JsonRpcRequest::new).collect();
        let resp: BatchResponse = self.send_impl(&request)?;

        let resp = resp.success()?;

        validate_batch(&self.state, &request, resp)
    }

    // Executes the specified request method using the given parameters by contacting the JSON RPC
    // server. If the 'http_proxy' or 'https_proxy' environment variable is set, enable the proxy.
    fn send_impl<S: Serialize, T: DeserializeOwned>(&self, payload: &S) -> Result<T> {
        let mut request = ureq::post(&self.url)
            .timeout_connect(REQUEST_TIMEOUT)
            .set("User-Agent", USER_AGENT)
            .build();

        let proxy = proxy::Proxy::new();
        let host = request.get_host().expect("unable to get the host");
        let scheme = request
            .get_scheme()
            .expect("Unable to get the scheme from the host");
        let proxy_url = match scheme.as_str() {
            "http" => proxy.http(&host),
            "https" => proxy.https(&host),
            _ => None,
        };
        if let Some(proxy_url) = proxy_url {
            request.set_proxy(ureq::Proxy::new(proxy_url).expect("Unable to parse proxy_url"));
        }

        let resp = request.send_json(serde_json::json!(payload));

        if resp.synthetic() {
            let e = resp.into_synthetic_error().unwrap();
            let error = match &e {
                ureq::Error::BadUrl(_)
                | ureq::Error::UnknownScheme(_)
                | ureq::Error::DnsFailed(_)
                | ureq::Error::BadHeader
                | ureq::Error::BadProxy
                | ureq::Error::BadProxyCreds
                | ureq::Error::ProxyConnect
                | ureq::Error::InvalidProxyCreds
                | ureq::Error::ConnectionFailed(_)
                | ureq::Error::TlsError(_) => Error::request(e),
                ureq::Error::Io(io_error) => {
                    if let std::io::ErrorKind::TimedOut = io_error.kind() {
                        Error::timeout(e)
                    } else {
                        Error::unknown(e)
                    }
                }
                _ => Error::unknown(e),
            };

            return Err(error);
        }

        if resp.status() != 200 {
            return Err(Error::status(resp.status()));
        }

        resp.into_json_deserialize().map_err(Error::decode)
    }
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, BTreeSet, HashMap};

// https://leetcode.com/problems/tweet-counts-per-frequency/
struct TweetCounts {
    map: HashMap<String, BTreeMap<i32, i32>>,
}

impl TweetCounts {
    fn new() -> Self {
        TweetCounts {
            map: HashMap::new(),
        }
    }

    fn record_tweet(&mut self, tweet_name: String, time: i32) {
        match self.map.get_mut(&tweet_name) {
            Some(m) => match m.get_mut(&time) {
                Some(m) => {
                    *m += 1;
                }
                None => {
                    m.insert(time, 1);
                }
            },
            None => {
                let mut m: BTreeMap<i32, i32> = BTreeMap::new();
                m.insert(time, 1);
                self.map.insert(tweet_name, m);
            }
        }
    }

    fn get_tweet_counts_per_frequency(
        &self,
        freq: String,
        tweet_name: String,
        start_time: i32,
        end_time: i32,
    ) -> Vec<i32> {
        match tweet_name.as_str() {
            "minute" => {
                let mut time = start_time;
                while time < end_time {
                    time += 60;
                }
            }
            "hour" => (),
            _ => (),
        };
        vec![]
    }
}

fn main() {
    let mut tweet_counts = TweetCounts::new();
    tweet_counts.record_tweet("tweet3".to_string(), 0);
    tweet_counts.record_tweet("tweet3".to_string(), 60);
    tweet_counts.record_tweet("tweet3".to_string(), 60);
    tweet_counts.record_tweet("tweet3".to_string(), 10);
    tweet_counts.record_tweet("tweet3".to_string(), 10);
    tweet_counts.get_tweet_counts_per_frequency("minute".to_string(), "tweet3".to_string(), 0, 59); // [3]
    tweet_counts.get_tweet_counts_per_frequency("minute".to_string(), "tweet3".to_string(), 0, 60); // [3,2]
    tweet_counts.record_tweet("tweet3".to_string(), 120);
    tweet_counts.get_tweet_counts_per_frequency("hour".to_string(), "tweet3".to_string(), 0, 210);
    // [6]
}
<commit_msg>Solve problem 1348<commit_after>use std::collections::{BTreeMap, HashMap};
use std::ops::Bound::{Excluded, Included};

// https://leetcode.com/problems/tweet-counts-per-frequency/
struct TweetCounts {
    map: HashMap<String, BTreeMap<i32, i32>>,
}

impl TweetCounts {
    fn new() -> Self {
        TweetCounts {
            map: HashMap::new(),
        }
    }

    fn record_tweet(&mut self, tweet_name: String, time: i32) {
        match self.map.get_mut(&tweet_name) {
            Some(m) => match m.get_mut(&time) {
                Some(m) => {
                    *m += 1;
                }
                None => {
                    m.insert(time, 1);
                }
            },
            None => {
                let mut m: BTreeMap<i32, i32> = BTreeMap::new();
                m.insert(time, 1);
                self.map.insert(tweet_name, m);
            }
        }
    }

    fn get_tweet_counts_per_frequency(
        &self,
        freq: String,
        tweet_name: String,
        start_time: i32,
        end_time: i32,
    ) -> Vec<i32> {
        fn f(
            map: &HashMap<String, BTreeMap<i32, i32>>,
            tweet_name: &String,
            start_time: i32,
            end_time: i32,
            chunk: i32,
            v: &mut Vec<i32>,
        ) {
            let mut time = start_time;
            while time <= end_time {
                match map.get(tweet_name) {
                    Some(m) => {
                        let count: i32 = m
                            .range((Included(time), Excluded((end_time + 1).min(time + chunk))))
                            .into_iter()
                            .map(|a| a.1)
                            .sum();
                        v.push(count);
                    }
                    None => v.push(0),
                }
                time += chunk;
            }
        }

        let mut v = vec![];
        match freq.as_str() {
            "minute" => f(&self.map, &tweet_name, start_time, end_time, 60, &mut v),
            "hour" => f(&self.map, &tweet_name, start_time, end_time, 3600, &mut v),
            _ => f(&self.map, &tweet_name, start_time, end_time, 86400, &mut v),
        };
        v
    }
}

fn main() {
    let mut tweet_counts = TweetCounts::new();
    tweet_counts.record_tweet("tweet3".to_string(), 0);
    tweet_counts.record_tweet("tweet3".to_string(), 60);
    tweet_counts.record_tweet("tweet3".to_string(), 60);
    tweet_counts.record_tweet("tweet3".to_string(), 10);
    tweet_counts.record_tweet("tweet3".to_string(), 10);
    println!(
        "{:?}",
        tweet_counts.get_tweet_counts_per_frequency(
            "minute".to_string(),
            "tweet3".to_string(),
            0,
            59
        )
    ); // [3]
    println!(
        "{:?}",
        tweet_counts.get_tweet_counts_per_frequency(
            "minute".to_string(),
            "tweet3".to_string(),
            0,
            60
        )
    ); // [3,2]
    tweet_counts.record_tweet("tweet3".to_string(), 120);
    println!(
        "{:?}",
        tweet_counts.get_tweet_counts_per_frequency(
            "hour".to_string(),
            "tweet3".to_string(),
            0,
            210
        )
    ); // [6]
    println!(
        "{:?}",
        tweet_counts.get_tweet_counts_per_frequency(
            "hour".to_string(),
            "tweet4".to_string(),
            0,
            210
        )
    ); // [0]
    println!(
        "{:?}",
        tweet_counts.get_tweet_counts_per_frequency(
            "hour".to_string(),
            "tweet3".to_string(),
            70,
            80
        )
    ); // [0]
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/jump-game-vi/
pub fn max_result(nums: Vec<i32>, k: i32) -> i32 {
    todo!()
}

fn main() {
    println!("{}", max_result(vec![1, -1, -2, 4, -7, 3], 2)); // 7
    println!("{}", max_result(vec![10, -5, -2, 4, 0, 3], 3)); // 17
    println!("{}", max_result(vec![1, -5, -20, 4, -1, 3, -6, -3], 2)); // 0
}
<commit_msg>Update proble 1696<commit_after>// https://leetcode.com/problems/jump-game-vi/
pub fn max_result(nums: Vec<i32>, k: i32) -> i32 {
    fn f(nums: &Vec<i32>, k: i32, index: i32, memo: &mut Vec<i32>) -> i32 {
        if index == nums.len() as i32 - 1 {
            return nums[index as usize];
        }
        if memo[index as usize] != i32::MIN {
            return memo[index as usize];
        }
        let mut max = i32::MIN;
        for i in (index + 1)..=(nums.len() as i32 - 1).min(index + k) {
            let mut x = f(nums, k, i, memo);
            if x != i32::MIN {
                x += nums[index as usize];
            }
            max = max.max(x);
        }
        memo[index as usize] = max;
        max
    }

    f(&nums, k, 0, &mut vec![i32::MIN; nums.len()])
}

fn main() {
    println!("{}", max_result(vec![1, -1, -2, 4, -7, 3], 2)); // 7
    println!("{}", max_result(vec![10, -5, -2, 4, 0, 3], 3)); // 17
    println!("{}", max_result(vec![1, -5, -20, 4, -1, 3, -6, -3], 2)); // 0
    println!("{}", max_result(vec![3, -6, -3], 2)); // 0
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/longest-palindrome-by-concatenating-two-letter-words/
pub fn longest_palindrome(words: Vec<String>) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        longest_palindrome(vec!["lc".to_string(), "cl".to_string(), "gg".to_string()])
    ); // 6
    println!(
        "{}",
        longest_palindrome(vec![
            "ab".to_string(),
            "ty".to_string(),
            "yt".to_string(),
            "lc".to_string(),
            "cl".to_string(),
            "ab".to_string()
        ])
    ); // 8
    println!(
        "{}",
        longest_palindrome(vec!["cc".to_string(), "ll".to_string(), "xx".to_string()])
    ); // 2
}
<commit_msg>Update problem 2131<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/longest-palindrome-by-concatenating-two-letter-words/
pub fn longest_palindrome(words: Vec<String>) -> i32 {
    let mut map: HashMap<String, i32> = HashMap::new();
    for word in words.into_iter() {
        *map.entry(word).or_insert(0) += 1;
    }
    let mut answer = 0;
    while let Some((word, count)) = map.iter().next() {
        let bytes = word.as_bytes();
        if bytes[0] == bytes[1] {
            answer += *count * 2;
            map.remove(&word.clone());
        } else {
            let reversed_word: String = word.chars().rev().collect();
            if let Some(c) = map.get(&reversed_word) {
                answer += count.min(c) * 4;
                map.remove(&word.clone());
                map.remove(&reversed_word);
            } else {
                map.remove(&word.clone());
            }
        }
    }
    answer
}

fn main() {
    // println!(
    //     "{}",
    //     longest_palindrome(vec!["lc".to_string(), "cl".to_string(), "gg".to_string()])
    // ); // 6
    // println!(
    //     "{}",
    //     longest_palindrome(vec![
    //         "ab".to_string(),
    //         "ty".to_string(),
    //         "yt".to_string(),
    //         "lc".to_string(),
    //         "cl".to_string(),
    //         "ab".to_string()
    //     ])
    // ); // 8
    // println!(
    //     "{}",
    //     longest_palindrome(vec!["cc".to_string(), "ll".to_string(), "xx".to_string()])
    // ); // 2
    // println!(
    //     "{}",
    //     longest_palindrome(vec![
    //         "lc".to_string(),
    //         "cl".to_string(),
    //         "gg".to_string(),
    //         "gg".to_string(),
    //         "gg".to_string(),
    //         "aa".to_string(),
    //         "aa".to_string()
    //     ])
    // ); // 14
    println!(
        "{}",
        longest_palindrome(vec![
            "lc".to_string(),
            "cl".to_string(),
            "gg".to_string(),
            "gg".to_string(),
            "gg".to_string(),
            "aa".to_string()
        ])
    ); // 10
}
<|endoftext|>