<commit_before>use crate::*;
use rustc::mir;
use rustc::ty::layout::Size;
use std::iter;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: &str,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>,
        _ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_mut();
        let tcx = &{ this.tcx.tcx };

        match link_name {
            // Windows API stubs.
            // HANDLE = isize
            // DWORD = ULONG = u32
            // BOOL = i32

            // Environment related shims
            "GetEnvironmentVariableW" => {
                // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
                // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars)
                // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string.
                // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator.
                // Return 0 upon failure.

                // This is not the env var you are looking for.
                this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND
                this.write_null(dest)?;
            }

            "SetEnvironmentVariableW" => {
                // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
                // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars)
                // Return nonzero if success, else return 0.
                throw_unsup_format!("can't set environment variable on Windows");
            }

            // File related shims
            "WriteFile" => {
                let handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
                let buf = this.read_scalar(args[1])?.not_undef()?;
                let n = this.read_scalar(args[2])?.to_u32()?;
                let written_place = this.deref_operand(args[3])?;
                // Spec says to always write `0` first.
                this.write_null(written_place.into())?;
                let written = if handle == -11 || handle == -12 {
                    // stdout/stderr
                    use std::io::{self, Write};

                    let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
                    let res = if handle == -11 {
                        io::stdout().write(buf_cont)
                    } else {
                        io::stderr().write(buf_cont)
                    };
                    res.ok().map(|n| n as u32)
                } else {
                    eprintln!("Miri: Ignored output to handle {}", handle);
                    // Pretend it all went well.
                    Some(n)
                };
                // If there was no error, write back how much was written.
                if let Some(n) = written {
                    this.write_scalar(Scalar::from_u32(n), written_place.into())?;
                }
                // Return whether this was a success.
                this.write_scalar(
                    Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
                    dest,
                )?;
            }

            // Other shims
            "GetProcessHeap" => {
                // Just fake a HANDLE
                this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?;
            }
            "HeapAlloc" => {
                let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
                let flags = this.read_scalar(args[1])?.to_u32()?;
                let size = this.read_scalar(args[2])?.to_machine_usize(this)?;
                let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
                let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
                this.write_scalar(res, dest)?;
            }
            "HeapFree" => {
                let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
                let _flags = this.read_scalar(args[1])?.to_u32()?;
                let ptr = this.read_scalar(args[2])?.not_undef()?;
                this.free(ptr, MiriMemoryKind::WinHeap)?;
                this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?;
            }
            "HeapReAlloc" => {
                let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
                let _flags = this.read_scalar(args[1])?.to_u32()?;
                let ptr = this.read_scalar(args[2])?.not_undef()?;
                let size = this.read_scalar(args[3])?.to_machine_usize(this)?;
                let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
                this.write_scalar(res, dest)?;
            }

            "SetLastError" => {
                this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?;
            }
            "GetLastError" => {
                let last_error = this.get_last_error()?;
                this.write_scalar(last_error, dest)?;
            }

            "AddVectoredExceptionHandler" => {
                // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
                this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
            }

            | "InitializeCriticalSection"
            | "EnterCriticalSection"
            | "LeaveCriticalSection"
            | "DeleteCriticalSection"
            => {
                // Nothing to do, not even a return value.
            }

            | "GetModuleHandleW"
            | "GetProcAddress"
            | "TryEnterCriticalSection"
            | "GetConsoleScreenBufferInfo"
            | "SetConsoleTextAttribute"
            => {
                // Pretend these do not exist / nothing happened, by returning zero.
                this.write_null(dest)?;
            }

            "GetSystemInfo" => {
                let system_info = this.deref_operand(args[0])?;
                // Initialize with `0`.
                this.memory.write_bytes(
                    system_info.ptr,
                    iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
                )?;
                // Set number of processors.
                let dword_size = Size::from_bytes(4);
                let num_cpus = this.mplace_field(system_info, 6)?;
                this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?;
            }

            "TlsAlloc" => {
                // This just creates a key; Windows does not natively support TLS destructors.

                // Create key and return it.
                let key = this.machine.tls.create_tls_key(None) as u128;

                // Figure out how large a TLS key actually is. This is `c::DWORD`.
                if dest.layout.size.bits() < 128
                    && key >= (1u128 << dest.layout.size.bits() as u128)
                {
                    throw_unsup!(OutOfTls);
                }
                this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
            }
            "TlsGetValue" => {
                let key = this.read_scalar(args[0])?.to_u32()? as u128;
                let ptr = this.machine.tls.load_tls(key, tcx)?;
                this.write_scalar(ptr, dest)?;
            }
            "TlsSetValue" => {
                let key = this.read_scalar(args[0])?.to_u32()? as u128;
                let new_ptr = this.read_scalar(args[1])?.not_undef()?;
                this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;

                // Return success (`1`).
                this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
            }
            "GetStdHandle" => {
                let which = this.read_scalar(args[0])?.to_i32()?;
                // We just make this the identity function, so we know later in `WriteFile`
                // which one it is.
                this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
            }
            "GetConsoleMode" => {
                // Everything is a pipe.
                this.write_null(dest)?;
            }
            "GetCommandLineW" => {
                this.write_scalar(
                    this.machine.cmd_line.expect("machine must be initialized"),
                    dest,
                )?;
            }
            // The actual name of 'RtlGenRandom'
            "SystemFunction036" => {
                let ptr = this.read_scalar(args[0])?.not_undef()?;
                let len = this.read_scalar(args[1])?.to_u32()?;
                this.gen_random(ptr, len as usize)?;
                this.write_scalar(Scalar::from_bool(true), dest)?;
            }
            // We don't support threading.
            "CreateThread" => {
                throw_unsup_format!("Miri does not support threading");
            }
            _ => throw_unsup_format!("can't call foreign function: {}", link_name),
        }

        Ok(true)
    }
}

<commit_msg>Auto merge of #1196 - RalfJung:winlock, r=RalfJung<commit_after>use crate::*;
use rustc::mir;
use rustc::ty::layout::Size;
use std::iter;

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: &str,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>,
        _ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_mut();
        let tcx = &{ this.tcx.tcx };

        match link_name {
            // Windows API stubs.
            // HANDLE = isize
            // DWORD = ULONG = u32
            // BOOL = i32

            // Environment related shims
            "GetEnvironmentVariableW" => {
                // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
                // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars)
                // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string.
                // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator.
                // Return 0 upon failure.

                // This is not the env var you are looking for.
                this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND
                this.write_null(dest)?;
            }

            "SetEnvironmentVariableW" => {
                // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars)
                // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars)
                // Return nonzero if success, else return 0.
                throw_unsup_format!("can't set environment variable on Windows");
            }

            // File related shims
            "WriteFile" => {
                let handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
                let buf = this.read_scalar(args[1])?.not_undef()?;
                let n = this.read_scalar(args[2])?.to_u32()?;
                let written_place = this.deref_operand(args[3])?;
                // Spec says to always write `0` first.
                this.write_null(written_place.into())?;
                let written = if handle == -11 || handle == -12 {
                    // stdout/stderr
                    use std::io::{self, Write};

                    let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?;
                    let res = if handle == -11 {
                        io::stdout().write(buf_cont)
                    } else {
                        io::stderr().write(buf_cont)
                    };
                    res.ok().map(|n| n as u32)
                } else {
                    eprintln!("Miri: Ignored output to handle {}", handle);
                    // Pretend it all went well.
                    Some(n)
                };
                // If there was no error, write back how much was written.
                if let Some(n) = written {
                    this.write_scalar(Scalar::from_u32(n), written_place.into())?;
                }
                // Return whether this was a success.
                this.write_scalar(
                    Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size),
                    dest,
                )?;
            }

            // Other shims
            "GetProcessHeap" => {
                // Just fake a HANDLE
                this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?;
            }
            "HeapAlloc" => {
                let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
                let flags = this.read_scalar(args[1])?.to_u32()?;
                let size = this.read_scalar(args[2])?.to_machine_usize(this)?;
                let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY
                let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap);
                this.write_scalar(res, dest)?;
            }
            "HeapFree" => {
                let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
                let _flags = this.read_scalar(args[1])?.to_u32()?;
                let ptr = this.read_scalar(args[2])?.not_undef()?;
                this.free(ptr, MiriMemoryKind::WinHeap)?;
                this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?;
            }
            "HeapReAlloc" => {
                let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?;
                let _flags = this.read_scalar(args[1])?.to_u32()?;
                let ptr = this.read_scalar(args[2])?.not_undef()?;
                let size = this.read_scalar(args[3])?.to_machine_usize(this)?;
                let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
                this.write_scalar(res, dest)?;
            }

            "SetLastError" => {
                this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?;
            }
            "GetLastError" => {
                let last_error = this.get_last_error()?;
                this.write_scalar(last_error, dest)?;
            }

            "AddVectoredExceptionHandler" => {
                // Any non zero value works for the stdlib. This is just used for stack overflows anyway.
                this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
            }

            | "InitializeCriticalSection"
            | "EnterCriticalSection"
            | "LeaveCriticalSection"
            | "DeleteCriticalSection"
            => {
                // Nothing to do, not even a return value.
                // (Windows locks are reentrant, and we have only 1 thread,
                // so not doing any futher checks here is at least not incorrect.)
            }

            | "GetModuleHandleW"
            | "GetProcAddress"
            | "GetConsoleScreenBufferInfo"
            | "SetConsoleTextAttribute"
            => {
                // Pretend these do not exist / nothing happened, by returning zero.
                this.write_null(dest)?;
            }

            "GetSystemInfo" => {
                let system_info = this.deref_operand(args[0])?;
                // Initialize with `0`.
                this.memory.write_bytes(
                    system_info.ptr,
                    iter::repeat(0u8).take(system_info.layout.size.bytes() as usize),
                )?;
                // Set number of processors.
                let dword_size = Size::from_bytes(4);
                let num_cpus = this.mplace_field(system_info, 6)?;
                this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?;
            }

            "TlsAlloc" => {
                // This just creates a key; Windows does not natively support TLS destructors.

                // Create key and return it.
                let key = this.machine.tls.create_tls_key(None) as u128;

                // Figure out how large a TLS key actually is. This is `c::DWORD`.
                if dest.layout.size.bits() < 128
                    && key >= (1u128 << dest.layout.size.bits() as u128)
                {
                    throw_unsup!(OutOfTls);
                }
                this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
            }
            "TlsGetValue" => {
                let key = this.read_scalar(args[0])?.to_u32()? as u128;
                let ptr = this.machine.tls.load_tls(key, tcx)?;
                this.write_scalar(ptr, dest)?;
            }
            "TlsSetValue" => {
                let key = this.read_scalar(args[0])?.to_u32()? as u128;
                let new_ptr = this.read_scalar(args[1])?.not_undef()?;
                this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?;

                // Return success (`1`).
                this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?;
            }
            "GetStdHandle" => {
                let which = this.read_scalar(args[0])?.to_i32()?;
                // We just make this the identity function, so we know later in `WriteFile`
                // which one it is.
                this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?;
            }
            "GetConsoleMode" => {
                // Everything is a pipe.
                this.write_null(dest)?;
            }
            "GetCommandLineW" => {
                this.write_scalar(
                    this.machine.cmd_line.expect("machine must be initialized"),
                    dest,
                )?;
            }
            // The actual name of 'RtlGenRandom'
            "SystemFunction036" => {
                let ptr = this.read_scalar(args[0])?.not_undef()?;
                let len = this.read_scalar(args[1])?.to_u32()?;
                this.gen_random(ptr, len as usize)?;
                this.write_scalar(Scalar::from_bool(true), dest)?;
            }
            // We don't support threading.
            "CreateThread" => {
                throw_unsup_format!("Miri does not support threading");
            }
            _ => throw_unsup_format!("can't call foreign function: {}", link_name),
        }

        Ok(true)
    }
}

<|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 std::char;

#[test]
fn test_is_lowercase() {
    assert!('a'.is_lowercase());
    assert!('ö'.is_lowercase());
    assert!('ß'.is_lowercase());
    assert!(!'Ü'.is_lowercase());
    assert!(!'P'.is_lowercase());
}

#[test]
fn test_is_uppercase() {
    assert!(!'h'.is_uppercase());
    assert!(!'ä'.is_uppercase());
    assert!(!'ß'.is_uppercase());
    assert!('Ö'.is_uppercase());
    assert!('T'.is_uppercase());
}

#[test]
fn test_is_whitespace() {
    assert!(' '.is_whitespace());
    assert!('\u{2007}'.is_whitespace());
    assert!('\t'.is_whitespace());
    assert!('\n'.is_whitespace());
    assert!(!'a'.is_whitespace());
    assert!(!'_'.is_whitespace());
    assert!(!'\u{0}'.is_whitespace());
}

#[test]
fn test_to_digit() {
    assert_eq!('0'.to_digit(10), Some(0));
    assert_eq!('1'.to_digit(2), Some(1));
    assert_eq!('2'.to_digit(3), Some(2));
    assert_eq!('9'.to_digit(10), Some(9));
    assert_eq!('a'.to_digit(16), Some(10));
    assert_eq!('A'.to_digit(16), Some(10));
    assert_eq!('b'.to_digit(16), Some(11));
    assert_eq!('B'.to_digit(16), Some(11));
    assert_eq!('z'.to_digit(36), Some(35));
    assert_eq!('Z'.to_digit(36), Some(35));
    assert_eq!(' '.to_digit(10), None);
    assert_eq!('$'.to_digit(36), None);
}

#[test]
fn test_to_lowercase() {
    fn lower(c: char) -> Vec<char> {
        c.to_lowercase().collect()
    }
    assert_eq!(lower('A'), ['a']);
    assert_eq!(lower('Ö'), ['ö']);
    assert_eq!(lower('ß'), ['ß']);
    assert_eq!(lower('Ü'), ['ü']);
    assert_eq!(lower('💩'), ['💩']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('Τ'), ['τ']);
    assert_eq!(lower('Ι'), ['ι']);
    assert_eq!(lower('Γ'), ['γ']);
    assert_eq!(lower('Μ'), ['μ']);
    assert_eq!(lower('Α'), ['α']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('ǅ'), ['ǆ']);
    assert_eq!(lower('ﬁ'), ['ﬁ']);
    assert_eq!(lower('İ'), ['i', '\u{307}']);
}

#[test]
fn test_to_uppercase() {
    fn upper(c: char) -> Vec<char> {
        c.to_uppercase().collect()
    }
    assert_eq!(upper('a'), ['A']);
    assert_eq!(upper('ö'), ['Ö']);
    assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s
    assert_eq!(upper('ü'), ['Ü']);
    assert_eq!(upper('💩'), ['💩']);

    assert_eq!(upper('σ'), ['Σ']);
    assert_eq!(upper('τ'), ['Τ']);
    assert_eq!(upper('ι'), ['Ι']);
    assert_eq!(upper('γ'), ['Γ']);
    assert_eq!(upper('μ'), ['Μ']);
    assert_eq!(upper('α'), ['Α']);
    assert_eq!(upper('ς'), ['Σ']);
    assert_eq!(upper('ǅ'), ['Ǆ']);
    assert_eq!(upper('ﬁ'), ['F', 'I']);
    assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']);
}

#[test]
fn test_is_control() {
    assert!('\u{0}'.is_control());
    assert!('\u{3}'.is_control());
    assert!('\u{6}'.is_control());
    assert!('\u{9}'.is_control());
    assert!('\u{7f}'.is_control());
    assert!('\u{92}'.is_control());
    assert!(!'\u{20}'.is_control());
    assert!(!'\u{55}'.is_control());
    assert!(!'\u{68}'.is_control());
}

#[test]
fn test_is_digit() {
   assert!('2'.is_numeric());
   assert!('7'.is_numeric());
   assert!(!'c'.is_numeric());
   assert!(!'i'.is_numeric());
   assert!(!'z'.is_numeric());
   assert!(!'Q'.is_numeric());
}

#[test]
fn test_escape_default() {
    fn string(c: char) -> String {
        c.escape_default().collect()
    }
    let s = string('\n');
    assert_eq!(s, "\\n");
    let s = string('\r');
    assert_eq!(s, "\\r");
    let s = string('\'');
    assert_eq!(s, "\\'");
    let s = string('"');
    assert_eq!(s, "\\\"");
    let s = string(' ');
    assert_eq!(s, " ");
    let s = string('a');
    assert_eq!(s, "a");
    let s = string('~');
    assert_eq!(s, "~");
    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\x1f');
    assert_eq!(s, "\\u{1f}");
    let s = string('\x7f');
    assert_eq!(s, "\\u{7f}");
    let s = string('\u{ff}');
    assert_eq!(s, "\\u{ff}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_escape_unicode() {
    fn string(c: char) -> String { c.escape_unicode().collect() }

    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\n');
    assert_eq!(s, "\\u{a}");
    let s = string(' ');
    assert_eq!(s, "\\u{20}");
    let s = string('a');
    assert_eq!(s, "\\u{61}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_encode_utf8() {
    fn check(input: char, expect: &[u8]) {
        assert_eq!(input.encode_utf8().as_slice(), expect);
        for (a, b) in input.encode_utf8().zip(expect) {
            assert_eq!(a, *b);
        }
    }

    check('x', &[0x78]);
    check('\u{e9}', &[0xc3, 0xa9]);
    check('\u{a66e}', &[0xea, 0x99, 0xae]);
    check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]);
}

#[test]
fn test_encode_utf16() {
    fn check(input: char, expect: &[u16]) {
        assert_eq!(input.encode_utf16().as_slice(), expect);
        for (a, b) in input.encode_utf16().zip(expect) {
            assert_eq!(a, *b);
        }
    }

    check('x', &[0x0078]);
    check('\u{e9}', &[0x00e9]);
    check('\u{a66e}', &[0xa66e]);
    check('\u{1f4a9}', &[0xd83d, 0xdca9]);
}

#[test]
fn test_len_utf16() {
    assert!('x'.len_utf16() == 1);
    assert!('\u{e9}'.len_utf16() == 1);
    assert!('\u{a66e}'.len_utf16() == 1);
    assert!('\u{1f4a9}'.len_utf16() == 2);
}

#[test]
fn test_decode_utf16() {
    fn check(s: &[u16], expected: &[Result<char, u16>]) {
        let v = char::decode_utf16(s.iter().cloned())
                     .map(|r| r.map_err(|e| e.unpaired_surrogate()))
                     .collect::<Vec<_>>();
        assert_eq!(v, expected);
    }
    check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]);
    check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]);
}

#[test]
fn ed_iterator_specializations() {
    // Check counting
    assert_eq!('\n'.escape_default().count(), 2);
    assert_eq!('c'.escape_default().count(), 1);
    assert_eq!(' '.escape_default().count(), 1);
    assert_eq!('\\'.escape_default().count(), 2);
    assert_eq!('\''.escape_default().count(), 2);

    // Check nth

    // Check that OoB is handled correctly
    assert_eq!('\n'.escape_default().nth(2), None);
    assert_eq!('c'.escape_default().nth(1), None);
    assert_eq!(' '.escape_default().nth(1), None);
    assert_eq!('\\'.escape_default().nth(2), None);
    assert_eq!('\''.escape_default().nth(2), None);

    // Check the first char
    assert_eq!('\n'.escape_default().nth(0), Some('\\'));
    assert_eq!('c'.escape_default().nth(0), Some('c'));
    assert_eq!(' '.escape_default().nth(0), Some(' '));
    assert_eq!('\\'.escape_default().nth(0), Some('\\'));
    assert_eq!('\''.escape_default().nth(0), Some('\\'));

    // Check the second char
    assert_eq!('\n'.escape_default().nth(1), Some('n'));
    assert_eq!('\\'.escape_default().nth(1), Some('\\'));
    assert_eq!('\''.escape_default().nth(1), Some('\''));

    // Check the last char
    assert_eq!('\n'.escape_default().last(), Some('n'));
    assert_eq!('c'.escape_default().last(), Some('c'));
    assert_eq!(' '.escape_default().last(), Some(' '));
    assert_eq!('\\'.escape_default().last(), Some('\\'));
    assert_eq!('\''.escape_default().last(), Some('\''));
}

#[test]
fn eu_iterator_specializations() {
    fn check(c: char) {
        let len = c.escape_unicode().count();

        // Check OoB
        assert_eq!(c.escape_unicode().nth(len), None);

        // For all possible in-bound offsets
        let mut iter = c.escape_unicode();
        for offset in 0..len {
            // Check last
            assert_eq!(iter.clone().last(), Some('}'));

            // Check counting
            assert_eq!(iter.clone().count(), len - offset);

            // Check nth
            assert_eq!(c.escape_unicode().nth(offset), iter.next());
        }

        // Check post-last
        assert_eq!(iter.clone().last(), None);
        assert_eq!(iter.clone().count(), 0);
    }

    check('\u{0}');
    check('\u{1}');
    check('\u{12}');
    check('\u{123}');
    check('\u{1234}');
    check('\u{12340}');
    check('\u{10FFFF}');
}
<commit_msg>Extend the test for `EscapeUnicode`<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 std::char;

#[test]
fn test_is_lowercase() {
    assert!('a'.is_lowercase());
    assert!('ö'.is_lowercase());
    assert!('ß'.is_lowercase());
    assert!(!'Ü'.is_lowercase());
    assert!(!'P'.is_lowercase());
}

#[test]
fn test_is_uppercase() {
    assert!(!'h'.is_uppercase());
    assert!(!'ä'.is_uppercase());
    assert!(!'ß'.is_uppercase());
    assert!('Ö'.is_uppercase());
    assert!('T'.is_uppercase());
}

#[test]
fn test_is_whitespace() {
    assert!(' '.is_whitespace());
    assert!('\u{2007}'.is_whitespace());
    assert!('\t'.is_whitespace());
    assert!('\n'.is_whitespace());
    assert!(!'a'.is_whitespace());
    assert!(!'_'.is_whitespace());
    assert!(!'\u{0}'.is_whitespace());
}

#[test]
fn test_to_digit() {
    assert_eq!('0'.to_digit(10), Some(0));
    assert_eq!('1'.to_digit(2), Some(1));
    assert_eq!('2'.to_digit(3), Some(2));
    assert_eq!('9'.to_digit(10), Some(9));
    assert_eq!('a'.to_digit(16), Some(10));
    assert_eq!('A'.to_digit(16), Some(10));
    assert_eq!('b'.to_digit(16), Some(11));
    assert_eq!('B'.to_digit(16), Some(11));
    assert_eq!('z'.to_digit(36), Some(35));
    assert_eq!('Z'.to_digit(36), Some(35));
    assert_eq!(' '.to_digit(10), None);
    assert_eq!('$'.to_digit(36), None);
}

#[test]
fn test_to_lowercase() {
    fn lower(c: char) -> Vec<char> {
        c.to_lowercase().collect()
    }
    assert_eq!(lower('A'), ['a']);
    assert_eq!(lower('Ö'), ['ö']);
    assert_eq!(lower('ß'), ['ß']);
    assert_eq!(lower('Ü'), ['ü']);
    assert_eq!(lower('💩'), ['💩']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('Τ'), ['τ']);
    assert_eq!(lower('Ι'), ['ι']);
    assert_eq!(lower('Γ'), ['γ']);
    assert_eq!(lower('Μ'), ['μ']);
    assert_eq!(lower('Α'), ['α']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('ǅ'), ['ǆ']);
    assert_eq!(lower('ﬁ'), ['ﬁ']);
    assert_eq!(lower('İ'), ['i', '\u{307}']);
}

#[test]
fn test_to_uppercase() {
    fn upper(c: char) -> Vec<char> {
        c.to_uppercase().collect()
    }
    assert_eq!(upper('a'), ['A']);
    assert_eq!(upper('ö'), ['Ö']);
    assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s
    assert_eq!(upper('ü'), ['Ü']);
    assert_eq!(upper('💩'), ['💩']);

    assert_eq!(upper('σ'), ['Σ']);
    assert_eq!(upper('τ'), ['Τ']);
    assert_eq!(upper('ι'), ['Ι']);
    assert_eq!(upper('γ'), ['Γ']);
    assert_eq!(upper('μ'), ['Μ']);
    assert_eq!(upper('α'), ['Α']);
    assert_eq!(upper('ς'), ['Σ']);
    assert_eq!(upper('ǅ'), ['Ǆ']);
    assert_eq!(upper('ﬁ'), ['F', 'I']);
    assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']);
}

#[test]
fn test_is_control() {
    assert!('\u{0}'.is_control());
    assert!('\u{3}'.is_control());
    assert!('\u{6}'.is_control());
    assert!('\u{9}'.is_control());
    assert!('\u{7f}'.is_control());
    assert!('\u{92}'.is_control());
    assert!(!'\u{20}'.is_control());
    assert!(!'\u{55}'.is_control());
    assert!(!'\u{68}'.is_control());
}

#[test]
fn test_is_digit() {
   assert!('2'.is_numeric());
   assert!('7'.is_numeric());
   assert!(!'c'.is_numeric());
   assert!(!'i'.is_numeric());
   assert!(!'z'.is_numeric());
   assert!(!'Q'.is_numeric());
}

#[test]
fn test_escape_default() {
    fn string(c: char) -> String {
        c.escape_default().collect()
    }
    let s = string('\n');
    assert_eq!(s, "\\n");
    let s = string('\r');
    assert_eq!(s, "\\r");
    let s = string('\'');
    assert_eq!(s, "\\'");
    let s = string('"');
    assert_eq!(s, "\\\"");
    let s = string(' ');
    assert_eq!(s, " ");
    let s = string('a');
    assert_eq!(s, "a");
    let s = string('~');
    assert_eq!(s, "~");
    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\x1f');
    assert_eq!(s, "\\u{1f}");
    let s = string('\x7f');
    assert_eq!(s, "\\u{7f}");
    let s = string('\u{ff}');
    assert_eq!(s, "\\u{ff}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_escape_unicode() {
    fn string(c: char) -> String { c.escape_unicode().collect() }

    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\n');
    assert_eq!(s, "\\u{a}");
    let s = string(' ');
    assert_eq!(s, "\\u{20}");
    let s = string('a');
    assert_eq!(s, "\\u{61}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_encode_utf8() {
    fn check(input: char, expect: &[u8]) {
        assert_eq!(input.encode_utf8().as_slice(), expect);
        for (a, b) in input.encode_utf8().zip(expect) {
            assert_eq!(a, *b);
        }
    }

    check('x', &[0x78]);
    check('\u{e9}', &[0xc3, 0xa9]);
    check('\u{a66e}', &[0xea, 0x99, 0xae]);
    check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]);
}

#[test]
fn test_encode_utf16() {
    fn check(input: char, expect: &[u16]) {
        assert_eq!(input.encode_utf16().as_slice(), expect);
        for (a, b) in input.encode_utf16().zip(expect) {
            assert_eq!(a, *b);
        }
    }

    check('x', &[0x0078]);
    check('\u{e9}', &[0x00e9]);
    check('\u{a66e}', &[0xa66e]);
    check('\u{1f4a9}', &[0xd83d, 0xdca9]);
}

#[test]
fn test_len_utf16() {
    assert!('x'.len_utf16() == 1);
    assert!('\u{e9}'.len_utf16() == 1);
    assert!('\u{a66e}'.len_utf16() == 1);
    assert!('\u{1f4a9}'.len_utf16() == 2);
}

#[test]
fn test_decode_utf16() {
    fn check(s: &[u16], expected: &[Result<char, u16>]) {
        let v = char::decode_utf16(s.iter().cloned())
                     .map(|r| r.map_err(|e| e.unpaired_surrogate()))
                     .collect::<Vec<_>>();
        assert_eq!(v, expected);
    }
    check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]);
    check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]);
}

#[test]
fn ed_iterator_specializations() {
    // Check counting
    assert_eq!('\n'.escape_default().count(), 2);
    assert_eq!('c'.escape_default().count(), 1);
    assert_eq!(' '.escape_default().count(), 1);
    assert_eq!('\\'.escape_default().count(), 2);
    assert_eq!('\''.escape_default().count(), 2);

    // Check nth

    // Check that OoB is handled correctly
    assert_eq!('\n'.escape_default().nth(2), None);
    assert_eq!('c'.escape_default().nth(1), None);
    assert_eq!(' '.escape_default().nth(1), None);
    assert_eq!('\\'.escape_default().nth(2), None);
    assert_eq!('\''.escape_default().nth(2), None);

    // Check the first char
    assert_eq!('\n'.escape_default().nth(0), Some('\\'));
    assert_eq!('c'.escape_default().nth(0), Some('c'));
    assert_eq!(' '.escape_default().nth(0), Some(' '));
    assert_eq!('\\'.escape_default().nth(0), Some('\\'));
    assert_eq!('\''.escape_default().nth(0), Some('\\'));

    // Check the second char
    assert_eq!('\n'.escape_default().nth(1), Some('n'));
    assert_eq!('\\'.escape_default().nth(1), Some('\\'));
    assert_eq!('\''.escape_default().nth(1), Some('\''));

    // Check the last char
    assert_eq!('\n'.escape_default().last(), Some('n'));
    assert_eq!('c'.escape_default().last(), Some('c'));
    assert_eq!(' '.escape_default().last(), Some(' '));
    assert_eq!('\\'.escape_default().last(), Some('\\'));
    assert_eq!('\''.escape_default().last(), Some('\''));
}

#[test]
fn eu_iterator_specializations() {
    fn check(c: char) {
        let len = c.escape_unicode().count();

        // Check OoB
        assert_eq!(c.escape_unicode().nth(len), None);

        // For all possible in-bound offsets
        let mut iter = c.escape_unicode();
        for offset in 0..len {
            // Check last
            assert_eq!(iter.clone().last(), Some('}'));

            // Check len
            assert_eq!(iter.len(), len - offset);

            // Check size_hint (= len in ExactSizeIterator)
            assert_eq!(iter.size_hint(), (iter.len(), Some(iter.len())));

            // Check counting
            assert_eq!(iter.clone().count(), len - offset);

            // Check nth
            assert_eq!(c.escape_unicode().nth(offset), iter.next());
        }

        // Check post-last
        assert_eq!(iter.clone().last(), None);
        assert_eq!(iter.clone().count(), 0);
    }

    check('\u{0}');
    check('\u{1}');
    check('\u{12}');
    check('\u{123}');
    check('\u{1234}');
    check('\u{12340}');
    check('\u{10FFFF}');
}
<|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 regex::Regex;
use std::ascii::AsciiExt;
use std::cmp;

#[deriving(Show, Clone)]
pub struct LogDirective {
    pub name: Option<String>,
    pub level: u32,
}

pub static LOG_LEVEL_NAMES: [&'static str, ..4] = ["ERROR", "WARN", "INFO",
                                               "DEBUG"];

/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
    from_str::<u32>(level).or_else(|| {
        let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
        pos.map(|p| p as u32 + 1)
    }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
/// and return a vector with log directives.
///
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
/// std::).  Also supports string log levels of error, warn, info, and debug
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<Regex>) {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return (dirs, None);
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match parse_log_level(part0) {
                    Some(num) => (num, None),
                    None => (::MAX_LOG_LEVEL, Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
            (Some(part0), Some(part1), None) => {
                match parse_log_level(part1) {
                    Some(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    let filter = filter.map_or(None, |filter| {
        match Regex::new(filter) {
            Ok(re) => Some(re),
            Err(e) => {
                println!("warning: invalid regex filter - {}", e);
                None
            }
        }
    });

    return (dirs, filter);
}

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

    #[test]
    fn parse_logging_spec_valid() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_crate() {
        // test parse_logging_spec with multiple = in specification
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_log_level() {
        // test parse_logging_spec with 'noNumber' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_string_log_level() {
        // test parse_logging_spec with 'warn' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::WARN);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_empty_log_level() {
        // test parse_logging_spec with '' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_global() {
        // test parse_logging_spec with no crate
        let (dirs, filter) = parse_logging_spec("warn,crate2=4");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 2);
        assert_eq!(dirs[0].name, None);
        assert_eq!(dirs[0].level, 2);
        assert_eq!(dirs[1].name, Some("crate2".to_string()));
        assert_eq!(dirs[1].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_valid_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_string().as_slice() == "abc");
    }

    #[test]
    fn parse_logging_spec_invalid_crate_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_string().as_slice() == "a.c");
    }

    #[test]
    fn parse_logging_spec_empty_with_filter() {
        let (dirs, filter) = parse_logging_spec("crate1/a*c");
        let dirs = dirs.as_slice();
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate1".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_some() && filter.unwrap().to_string().as_slice() == "a*c");
    }
}
<commit_msg>liblog: remove unnecessary `as_slice` calls<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 regex::Regex;
use std::ascii::AsciiExt;
use std::cmp;

#[deriving(Show, Clone)]
pub struct LogDirective {
    pub name: Option<String>,
    pub level: u32,
}

pub static LOG_LEVEL_NAMES: [&'static str, ..4] = ["ERROR", "WARN", "INFO",
                                               "DEBUG"];

/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
    from_str::<u32>(level).or_else(|| {
        let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
        pos.map(|p| p as u32 + 1)
    }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}

/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
/// and return a vector with log directives.
///
/// Valid log levels are 0-255, with the most likely ones being 1-4 (defined in
/// std::).  Also supports string log levels of error, warn, info, and debug
pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<Regex>) {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let filter = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return (dirs, None);
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match parse_log_level(part0) {
                    Some(num) => (num, None),
                    None => (::MAX_LOG_LEVEL, Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
            (Some(part0), Some(part1), None) => {
                match parse_log_level(part1) {
                    Some(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    let filter = filter.map_or(None, |filter| {
        match Regex::new(filter) {
            Ok(re) => Some(re),
            Err(e) => {
                println!("warning: invalid regex filter - {}", e);
                None
            }
        }
    });

    return (dirs, filter);
}

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

    #[test]
    fn parse_logging_spec_valid() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_crate() {
        // test parse_logging_spec with multiple = in specification
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_invalid_log_level() {
        // test parse_logging_spec with 'noNumber' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=noNumber,crate2=4");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_string_log_level() {
        // test parse_logging_spec with 'warn' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=warn");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::WARN);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_empty_log_level() {
        // test parse_logging_spec with '' as log level
        let (dirs, filter) = parse_logging_spec("crate1::mod1=wrong,crate2=");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_global() {
        // test parse_logging_spec with no crate
        let (dirs, filter) = parse_logging_spec("warn,crate2=4");
        assert_eq!(dirs.len(), 2);
        assert_eq!(dirs[0].name, None);
        assert_eq!(dirs[0].level, 2);
        assert_eq!(dirs[1].name, Some("crate2".to_string()));
        assert_eq!(dirs[1].level, 4);
        assert!(filter.is_none());
    }

    #[test]
    fn parse_logging_spec_valid_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1,crate1::mod2,crate2=4/abc");
        assert_eq!(dirs.len(), 3);
        assert_eq!(dirs[0].name, Some("crate1::mod1".to_string()));
        assert_eq!(dirs[0].level, 1);

        assert_eq!(dirs[1].name, Some("crate1::mod2".to_string()));
        assert_eq!(dirs[1].level, ::MAX_LOG_LEVEL);

        assert_eq!(dirs[2].name, Some("crate2".to_string()));
        assert_eq!(dirs[2].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_string() == "abc");
    }

    #[test]
    fn parse_logging_spec_invalid_crate_filter() {
        let (dirs, filter) = parse_logging_spec("crate1::mod1=1=2,crate2=4/a.c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate2".to_string()));
        assert_eq!(dirs[0].level, 4);
        assert!(filter.is_some() && filter.unwrap().to_string() == "a.c");
    }

    #[test]
    fn parse_logging_spec_empty_with_filter() {
        let (dirs, filter) = parse_logging_spec("crate1/a*c");
        assert_eq!(dirs.len(), 1);
        assert_eq!(dirs[0].name, Some("crate1".to_string()));
        assert_eq!(dirs[0].level, ::MAX_LOG_LEVEL);
        assert!(filter.is_some() && filter.unwrap().to_string() == "a*c");
    }
}
<|endoftext|>


<commit_before>use super::buckets::Buckets;
use super::metric::{Metric, MetricKind};
use std::collections::HashMap;
use std::cmp::Ordering;
use time;

/// Creates derived values from metric data.
///
/// Creates:
///
/// - timer percentile data.
/// - internal processing metrics
pub fn process(buckets: &mut Buckets) {
    let start_time = time::get_time();

    let mut timer_data = HashMap::new();

    // Add the various derived values for timers.
    for (key, values) in buckets.timers().iter() {
        let mut v = values.clone();
        v.sort_by(|a, b| a.partial_cmp(b).unwrap());

        timer_data.insert(format!("{}.min", key), v[0]);
        timer_data.insert(format!("{}.max", key), v[v.len() - 1]);
    }
    buckets.set_timer_data(timer_data);

    let duration = time::get_time() - start_time;
    let process_duration = Metric::new(
        "statsd.processing_time",
        duration.num_milliseconds() as f64,
        MetricKind::Counter(1.0));
    buckets.add(&process_duration);
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::buckets::Buckets;
    use super::super::metric::{Metric, MetricKind};
    use time;

    fn make_buckets() -> Buckets {
        let mut buckets = Buckets::new();

        let metrics = [
            Metric::new("some.timer", 13.1, MetricKind::Timer),
            Metric::new("some.timer", 33.7, MetricKind::Timer),
            Metric::new("some.timer", 3.4, MetricKind::Timer),
            Metric::new("some.timer", 12.1, MetricKind::Timer),
        ];
        for m in metrics.iter() {
            buckets.add(&m);
        }
        buckets
    }

    #[test]
    fn test_process_timer_data() {
        let mut buckets = make_buckets();
        process(&mut buckets);

        assert_eq!(Some(&3.4), buckets.timer_data().get("some.timer.min"));
        assert_eq!(Some(&33.7), buckets.timer_data().get("some.timer.max"));
    }

    #[test]
    fn test_set_internal_metrics() {
    }
}
<commit_msg>Add mean/median/count derived metrics.<commit_after>use super::buckets::Buckets;
use super::metric::{Metric, MetricKind};
use std::collections::HashMap;
use std::cmp::Ordering;
use time;

/// Creates derived values from metric data.
///
/// Creates:
///
/// - timer percentile data.
/// - internal processing metrics
pub fn process(buckets: &mut Buckets) {
    let start_time = time::get_time();

    let mut timer_data = HashMap::new();

    // Add the various derived values for timers.
    for (key, values) in buckets.timers().iter() {
        let mut v = values.clone();
        v.sort_by(|a, b| a.partial_cmp(b).unwrap());

        let len = v.len() as f64;
        let sum = v.iter().fold(0.0, |sum, x| sum + x);
        let mean = sum / len;

        let mid = (len / 2.0).floor() as usize;
        let median = if (v.len() % 2) == 0 {
            (v[mid - 1] + v[mid + 1]) / 2.0
        } else {
            v[mid]
        };

        timer_data.insert(format!("{}.min", key), v[0]);
        timer_data.insert(format!("{}.max", key), v[v.len() - 1]);
        timer_data.insert(format!("{}.count", key), len);
        timer_data.insert(format!("{}.mean", key), mean);
        timer_data.insert(format!("{}.median", key), median);
    }
    buckets.set_timer_data(timer_data);

    let duration = time::get_time() - start_time;
    let process_duration = Metric::new(
        "statsd.processing_time",
        duration.num_milliseconds() as f64,
        MetricKind::Counter(1.0));
    buckets.add(&process_duration);
}

#[cfg(test)]
mod test {
    use super::*;
    use super::super::buckets::Buckets;
    use super::super::metric::{Metric, MetricKind};
    use std::option::Option;
    use time;

    fn make_buckets() -> Buckets {
        let mut buckets = Buckets::new();

        let metrics = [
            Metric::new("some.timer", 13.1, MetricKind::Timer),
            Metric::new("some.timer", 33.7, MetricKind::Timer),
            Metric::new("some.timer", 3.4, MetricKind::Timer),
            Metric::new("some.timer", 12.1, MetricKind::Timer),
        ];
        for m in metrics.iter() {
            buckets.add(&m);
        }
        buckets
    }

    fn assert_float(expected: &str, value: &f64) {
        assert_eq!(expected, format!("{:.*}", 3, value));
    }

    #[test]
    fn test_process_timer_data() {
        let mut buckets = make_buckets();
        process(&mut buckets);

        assert_eq!(Some(&3.4), buckets.timer_data().get("some.timer.min"));
        assert_eq!(Some(&33.7), buckets.timer_data().get("some.timer.max"));
        assert_eq!(Some(&4.0), buckets.timer_data().get("some.timer.count"));
        assert_float(
            "15.575",
            buckets.timer_data().get("some.timer.mean").unwrap());
        assert_float(
            "22.900",
            buckets.timer_data().get("some.timer.median").unwrap());
    }

    #[test]
    fn test_set_internal_metrics() {
    }
}
<|endoftext|>


<commit_before>/*!

# GraphQL

[GraphQL][graphql] is a data query language developed by Facebook intended to
serve mobile and web application frontends.

*Juniper* makes it possible to write GraphQL servers in Rust that are
type-safe and blazingly fast. We also try to make declaring and resolving
GraphQL schemas as convenient as possible as Rust will allow.

Juniper does not include a web server - instead it provides building blocks to
make integration with existing servers straightforward. It optionally provides a
pre-built integration for the [Iron][iron] and [Rocket] frameworks, including
embedded [Graphiql][graphiql] for easy debugging.

* [Cargo crate](https://crates.io/crates/juniper)
* [API Reference][docsrs]
* [Book][book]: Guides and Examples

## Getting Started

The best place to get started is the [Juniper Book][book], which contains
guides with plenty of examples, covering all features of Juniper.

To get started quickly and get a feel for Juniper, check out the
[Quickstart][book_quickstart] section.

For specific information about macros, types and the Juniper api, the
[API Reference][docsrs] is the best place to look.

You can also check out [src/tests/schema.rs][test_schema_rs] to see a complex
schema including polymorphism with traits and interfaces.
For an example of web framework integration,
see the [rocket][rocket_examples] and [iron][iron_examples] examples folders.

## Features

Juniper supports the full GraphQL query language according to the
[specification][graphql_spec], including interfaces, unions, schema
introspection, and validations.
It does not, however, support the schema language.

As an exception to other GraphQL libraries for other languages, Juniper builds
non-null types by default. A field of type `Vec<Episode>` will be converted into
`[Episode!]!`. The corresponding Rust type for e.g. `[Episode]` would be
`Option<Vec<Option<Episode>>>`.

## Integrations

### Data types

Juniper has automatic integration with some very common Rust crates to make
building schemas a breeze. The types from these crates will be usable in
your Schemas automatically.

* [uuid][uuid]
* [url][url]
* [chrono][chrono]

### Web Frameworks

* [rocket][rocket]
* [iron][iron]

## API Stability

Juniper has not reached 1.0 yet, thus some API instability should be expected.

[graphql]: http://graphql.org
[graphiql]: https://github.com/graphql/graphiql
[iron]: http://ironframework.io
[graphql_spec]: http://facebook.github.io/graphql
[test_schema_rs]: https://github.com/graphql-rust/juniper/blob/master/juniper/src/tests/schema.rs
[tokio]: https://github.com/tokio-rs/tokio
[rocket_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_rocket/examples
[iron_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_iron/examples
[Rocket]: https://rocket.rs
[book]: https://graphql-rust.github.io/
[book_quickstart]: https://graphql-rust.github.io/quickstart.html
[docsrs]: https://docs.rs/juniper

[uuid]: https://crates.io/crates/uuid
[url]: https://crates.io/crates/url
[chrono]: https://crates.io/crates/chrono

*/
#![doc(html_root_url = "https://docs.rs/juniper/0.14.2")]
#![warn(missing_docs)]

#[doc(hidden)]
pub extern crate serde;

#[cfg(any(test, feature = "expose-test-schema"))]
extern crate serde_json;

#[cfg(any(test, feature = "chrono"))]
extern crate chrono;

#[cfg(any(test, feature = "url"))]
extern crate url;

#[cfg(any(test, feature = "uuid"))]
extern crate uuid;

// Depend on juniper_codegen and re-export everything in it.
// This allows users to just depend on juniper and get the derive
// functionality automatically.
pub use juniper_codegen::{
    graphql_object, graphql_union, GraphQLEnum, GraphQLInputObject, GraphQLObject,
    GraphQLScalarValue,
};
// Internal macros are not exported,
// but declared at the root to make them easier to use.
#[allow(unused_imports)]
use juniper_codegen::{
    graphql_object_internal, graphql_union_internal, GraphQLEnumInternal,
    GraphQLInputObjectInternal, GraphQLScalarValueInternal,
};

#[macro_use]
mod value;
#[macro_use]
mod macros;
mod ast;
mod executor;
mod introspection;
pub mod parser;
pub(crate) mod schema;
mod types;
mod util;
mod validation;
// This needs to be public until docs have support for private modules:
// https://github.com/rust-lang/cargo/issues/1520
pub mod http;
pub mod integrations;
// TODO: remove this alias export in 0.10. (breaking change)
pub use crate::http::graphiql;

#[cfg(all(test, not(feature = "expose-test-schema")))]
mod tests;
#[cfg(feature = "expose-test-schema")]
pub mod tests;

#[cfg(test)]
mod executor_tests;

// Needs to be public because macros use it.
pub use crate::util::to_camel_case;

use crate::{
    executor::{execute_validated_query, get_operation},
    introspection::{INTROSPECTION_QUERY, INTROSPECTION_QUERY_WITHOUT_DESCRIPTIONS},
    parser::{parse_document_source, ParseError, Spanning},
    validation::{validate_input_values, visit_all_rules, ValidatorContext},
};

pub use crate::{
    ast::{FromInputValue, InputValue, Selection, ToInputValue, Type},
    executor::{
        Applies, Context, ExecutionError, ExecutionResult, Executor, FieldError, FieldResult,
        FromContext, IntoFieldError, IntoResolvable, LookAheadArgument, LookAheadMethods,
        LookAheadSelection, LookAheadValue, Registry, Variables,
    },
    introspection::IntrospectionFormat,
    schema::{meta, model::RootNode},
    types::{
        base::{Arguments, GraphQLType, TypeKind},
        scalars::{EmptyMutation, ID},
    },
    validation::RuleError,
    value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value},
};

/// A pinned, boxed future that can be polled.
pub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + 'a + Send>>;

#[cfg(feature = "async")]
pub use crate::types::async_await::GraphQLTypeAsync;

/// An error that prevented query execution
#[derive(Debug, PartialEq)]
#[allow(missing_docs)]
pub enum GraphQLError<'a> {
    ParseError(Spanning<ParseError<'a>>),
    ValidationError(Vec<RuleError>),
    NoOperationProvided,
    MultipleOperationsProvided,
    UnknownOperationName,
    IsSubscription,
}

/// Execute a query in a provided schema
pub fn execute<'a, S, CtxT, QueryT, MutationT>(
    document_source: &'a str,
    operation_name: Option<&str>,
    root_node: &'a RootNode<QueryT, MutationT, S>,
    variables: &Variables<S>,
    context: &CtxT,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where
    S: ScalarValue,
    QueryT: GraphQLType<S, Context = CtxT>,
    MutationT: GraphQLType<S, Context = CtxT>,
{
    let document = parse_document_source(document_source, &root_node.schema)?;

    {
        let mut ctx = ValidatorContext::new(&root_node.schema, &document);
        visit_all_rules(&mut ctx, &document);

        let errors = ctx.into_errors();
        if !errors.is_empty() {
            return Err(GraphQLError::ValidationError(errors));
        }
    }

    let operation = get_operation(&document, operation_name)?;

    {
        let errors = validate_input_values(variables, operation, &root_node.schema);

        if !errors.is_empty() {
            return Err(GraphQLError::ValidationError(errors));
        }
    }

    execute_validated_query(&document, operation, root_node, variables, context)
}

/// Execute a query in a provided schema
#[cfg(feature = "async")]
pub async fn execute_async<'a, S, CtxT, QueryT, MutationT>(
    document_source: &'a str,
    operation_name: Option<&str>,
    root_node: &'a RootNode<'a, QueryT, MutationT, S>,
    variables: &Variables<S>,
    context: &CtxT,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where
    S: ScalarValue + Send + Sync,
    QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
    QueryT::TypeInfo: Send + Sync,
    MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
    MutationT::TypeInfo: Send + Sync,
    CtxT: Send + Sync,
{
    let document = parse_document_source(document_source, &root_node.schema)?;

    let operation = get_operation(&document, operation_name)?;

    {
        let errors = validate_input_values(variables, operation, &root_node.schema);

        if !errors.is_empty() {
            return Err(GraphQLError::ValidationError(errors));
        }
    }

    executor::execute_validated_query_async(&document, operation, root_node, variables, context)
        .await
}

/// Execute the reference introspection query in the provided schema
pub fn introspect<'a, S, CtxT, QueryT, MutationT>(
    root_node: &'a RootNode<QueryT, MutationT, S>,
    context: &CtxT,
    format: IntrospectionFormat,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where
    S: ScalarValue,
    QueryT: GraphQLType<S, Context = CtxT>,
    MutationT: GraphQLType<S, Context = CtxT>,
{
    execute(
        match format {
            IntrospectionFormat::All => INTROSPECTION_QUERY,
            IntrospectionFormat::WithoutDescriptions => INTROSPECTION_QUERY_WITHOUT_DESCRIPTIONS,
        },
        None,
        root_node,
        &Variables::new(),
        context,
    )
}

impl<'a> From<Spanning<ParseError<'a>>> for GraphQLError<'a> {
    fn from(f: Spanning<ParseError<'a>>) -> GraphQLError<'a> {
        GraphQLError::ParseError(f)
    }
}
<commit_msg>Fix formatting<commit_after>/*!

# GraphQL

[GraphQL][graphql] is a data query language developed by Facebook intended to
serve mobile and web application frontends.

*Juniper* makes it possible to write GraphQL servers in Rust that are
type-safe and blazingly fast. We also try to make declaring and resolving
GraphQL schemas as convenient as possible as Rust will allow.

Juniper does not include a web server - instead it provides building blocks to
make integration with existing servers straightforward. It optionally provides a
pre-built integration for the [Iron][iron] and [Rocket] frameworks, including
embedded [Graphiql][graphiql] for easy debugging.

* [Cargo crate](https://crates.io/crates/juniper)
* [API Reference][docsrs]
* [Book][book]: Guides and Examples

## Getting Started

The best place to get started is the [Juniper Book][book], which contains
guides with plenty of examples, covering all features of Juniper.

To get started quickly and get a feel for Juniper, check out the
[Quickstart][book_quickstart] section.

For specific information about macros, types and the Juniper api, the
[API Reference][docsrs] is the best place to look.

You can also check out [src/tests/schema.rs][test_schema_rs] to see a complex
schema including polymorphism with traits and interfaces.
For an example of web framework integration,
see the [rocket][rocket_examples] and [iron][iron_examples] examples folders.

## Features

Juniper supports the full GraphQL query language according to the
[specification][graphql_spec], including interfaces, unions, schema
introspection, and validations.
It does not, however, support the schema language.

As an exception to other GraphQL libraries for other languages, Juniper builds
non-null types by default. A field of type `Vec<Episode>` will be converted into
`[Episode!]!`. The corresponding Rust type for e.g. `[Episode]` would be
`Option<Vec<Option<Episode>>>`.

## Integrations

### Data types

Juniper has automatic integration with some very common Rust crates to make
building schemas a breeze. The types from these crates will be usable in
your Schemas automatically.

* [uuid][uuid]
* [url][url]
* [chrono][chrono]

### Web Frameworks

* [rocket][rocket]
* [iron][iron]

## API Stability

Juniper has not reached 1.0 yet, thus some API instability should be expected.

[graphql]: http://graphql.org
[graphiql]: https://github.com/graphql/graphiql
[iron]: http://ironframework.io
[graphql_spec]: http://facebook.github.io/graphql
[test_schema_rs]: https://github.com/graphql-rust/juniper/blob/master/juniper/src/tests/schema.rs
[tokio]: https://github.com/tokio-rs/tokio
[rocket_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_rocket/examples
[iron_examples]: https://github.com/graphql-rust/juniper/tree/master/juniper_iron/examples
[Rocket]: https://rocket.rs
[book]: https://graphql-rust.github.io/
[book_quickstart]: https://graphql-rust.github.io/quickstart.html
[docsrs]: https://docs.rs/juniper

[uuid]: https://crates.io/crates/uuid
[url]: https://crates.io/crates/url
[chrono]: https://crates.io/crates/chrono

*/
#![doc(html_root_url = "https://docs.rs/juniper/0.14.2")]
#![warn(missing_docs)]

#[doc(hidden)]
pub extern crate serde;

#[cfg(any(test, feature = "expose-test-schema"))]
extern crate serde_json;

#[cfg(any(test, feature = "chrono"))]
extern crate chrono;

#[cfg(any(test, feature = "url"))]
extern crate url;

#[cfg(any(test, feature = "uuid"))]
extern crate uuid;

// Depend on juniper_codegen and re-export everything in it.
// This allows users to just depend on juniper and get the derive
// functionality automatically.
pub use juniper_codegen::{
    graphql_object, graphql_union, GraphQLEnum, GraphQLInputObject, GraphQLObject,
    GraphQLScalarValue,
};
// Internal macros are not exported,
// but declared at the root to make them easier to use.
#[allow(unused_imports)]
use juniper_codegen::{
    graphql_object_internal, graphql_union_internal, GraphQLEnumInternal,
    GraphQLInputObjectInternal, GraphQLScalarValueInternal,
};

#[macro_use]
mod value;
#[macro_use]
mod macros;
mod ast;
mod executor;
mod introspection;
pub mod parser;
pub(crate) mod schema;
mod types;
mod util;
mod validation;
// This needs to be public until docs have support for private modules:
// https://github.com/rust-lang/cargo/issues/1520
pub mod http;
pub mod integrations;
// TODO: remove this alias export in 0.10. (breaking change)
pub use crate::http::graphiql;

#[cfg(all(test, not(feature = "expose-test-schema")))]
mod tests;
#[cfg(feature = "expose-test-schema")]
pub mod tests;

#[cfg(test)]
mod executor_tests;

// Needs to be public because macros use it.
pub use crate::util::to_camel_case;

use crate::{
    executor::{execute_validated_query, get_operation},
    introspection::{INTROSPECTION_QUERY, INTROSPECTION_QUERY_WITHOUT_DESCRIPTIONS},
    parser::{parse_document_source, ParseError, Spanning},
    validation::{validate_input_values, visit_all_rules, ValidatorContext},
};

pub use crate::{
    ast::{FromInputValue, InputValue, Selection, ToInputValue, Type},
    executor::{
        Applies, Context, ExecutionError, ExecutionResult, Executor, FieldError, FieldResult,
        FromContext, IntoFieldError, IntoResolvable, LookAheadArgument, LookAheadMethods,
        LookAheadSelection, LookAheadValue, Registry, Variables,
    },
    introspection::IntrospectionFormat,
    schema::{meta, model::RootNode},
    types::{
        base::{Arguments, GraphQLType, TypeKind},
        scalars::{EmptyMutation, ID},
    },
    validation::RuleError,
    value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value},
};

/// A pinned, boxed future that can be polled.
pub type BoxFuture<'a, T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + 'a + Send>>;

#[cfg(feature = "async")]
pub use crate::types::async_await::GraphQLTypeAsync;

/// An error that prevented query execution
#[derive(Debug, PartialEq)]
#[allow(missing_docs)]
pub enum GraphQLError<'a> {
    ParseError(Spanning<ParseError<'a>>),
    ValidationError(Vec<RuleError>),
    NoOperationProvided,
    MultipleOperationsProvided,
    UnknownOperationName,
    IsSubscription,
}

/// Execute a query in a provided schema
pub fn execute<'a, S, CtxT, QueryT, MutationT>(
    document_source: &'a str,
    operation_name: Option<&str>,
    root_node: &'a RootNode<QueryT, MutationT, S>,
    variables: &Variables<S>,
    context: &CtxT,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where
    S: ScalarValue,
    QueryT: GraphQLType<S, Context = CtxT>,
    MutationT: GraphQLType<S, Context = CtxT>,
{
    let document = parse_document_source(document_source, &root_node.schema)?;

    {
        let mut ctx = ValidatorContext::new(&root_node.schema, &document);
        visit_all_rules(&mut ctx, &document);

        let errors = ctx.into_errors();
        if !errors.is_empty() {
            return Err(GraphQLError::ValidationError(errors));
        }
    }

    let operation = get_operation(&document, operation_name)?;

    {
        let errors = validate_input_values(variables, operation, &root_node.schema);

        if !errors.is_empty() {
            return Err(GraphQLError::ValidationError(errors));
        }
    }

    execute_validated_query(&document, operation, root_node, variables, context)
}

/// Execute a query in a provided schema
#[cfg(feature = "async")]
pub async fn execute_async<'a, S, CtxT, QueryT, MutationT>(
    document_source: &'a str,
    operation_name: Option<&str>,
    root_node: &'a RootNode<'a, QueryT, MutationT, S>,
    variables: &Variables<S>,
    context: &CtxT,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where
    S: ScalarValue + Send + Sync,
    QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
    QueryT::TypeInfo: Send + Sync,
    MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
    MutationT::TypeInfo: Send + Sync,
    CtxT: Send + Sync,
{
    let document = parse_document_source(document_source, &root_node.schema)?;

    let operation = get_operation(&document, operation_name)?;

    {
        let errors = validate_input_values(variables, operation, &root_node.schema);

        if !errors.is_empty() {
            return Err(GraphQLError::ValidationError(errors));
        }
    }

    executor::execute_validated_query_async(&document, operation, root_node, variables, context)
        .await
}

/// Execute the reference introspection query in the provided schema
pub fn introspect<'a, S, CtxT, QueryT, MutationT>(
    root_node: &'a RootNode<QueryT, MutationT, S>,
    context: &CtxT,
    format: IntrospectionFormat,
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
where
    S: ScalarValue,
    QueryT: GraphQLType<S, Context = CtxT>,
    MutationT: GraphQLType<S, Context = CtxT>,
{
    execute(
        match format {
            IntrospectionFormat::All => INTROSPECTION_QUERY,
            IntrospectionFormat::WithoutDescriptions => INTROSPECTION_QUERY_WITHOUT_DESCRIPTIONS,
        },
        None,
        root_node,
        &Variables::new(),
        context,
    )
}

impl<'a> From<Spanning<ParseError<'a>>> for GraphQLError<'a> {
    fn from(f: Spanning<ParseError<'a>>) -> GraphQLError<'a> {
        GraphQLError::ParseError(f)
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map;

use render::Renderer;
use routing::{DagHandle, Edge, GraphWatcher, NodeData, NodeHandle};

type NodeMap = HashMap<NodeHandle, Node>;

#[derive(Default)]
pub struct RefRenderer {
    nodes: NodeMap,
}

struct Node {
    data: MyNodeData,
    inbound: HashSet<Edge>
}

enum MyNodeData {
    /// This node is a non-primitive effect.
    UserNode(NodeMap),
    /// This node is an instance of another DAG.
    Graph(DagHandle),
    /// Primitive Delay(samples) effect
    Delay(u64),
    /// Primitive Constant(value) effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    Constant(f32),
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// This node is a DAG definition. i.e. it holds the output edges of a DAG.
    DagIO,
}

impl Renderer for RefRenderer {
    fn get_sample(&mut self, time: u64, ch: u8) -> f32 {
        // Try to find the edge that goes to -> (Null, slot=0, ch=ch)
        let root_handle = NodeHandle::toplevel();
        // empty graph is 0 = silence
        self.nodes.get(&root_handle).map_or(0f32, |node| {
            // find all edges to ([Null], slot=0, ch=ch)
            self.sum_input_to_slot(&self.nodes, node, time, 0, ch, &Vec::new()) as f32
        })
    }
}
impl RefRenderer {
    /// Get the value on an edge at a particular time
    /// When backtracking from the output, we push each Node onto the context if we enter inside of
    ///   it (i.e. if it's a nested DAG) & pop when exiting.
    fn get_value(&self, nodes: &NodeMap, edge: &Edge, time: u64, context: &Vec<(&NodeMap, NodeHandle)>) -> f64 {
        let from = edge.from_full();
        if *from.node_handle() == None {
            // Reading from one of the inputs to the top of `context`
            // TODO: we can avoid cloning by reversing the pop after recursing.
            let mut new_context = context.clone();
            let (new_nodes, head) = new_context.pop().unwrap();
            // Sum the inputs to the matching slot/ch
            self.sum_input_to_slot(new_nodes, &new_nodes[&head], time, edge.from_slot(), edge.from_ch(), &new_context)
        } else {
            // Reading from another node within the DAG
            let node = &nodes[&from];
            match node.data {
                MyNodeData::UserNode(ref new_nodes) => {
                    let mut new_context = context.clone();
                    new_context.push((nodes, from));
                    // Now find the *output* of the sub dag (or 0 if the sub dag has no outputs)
                    new_nodes.get(&NodeHandle::toplevel()).map_or(0f64, |root_node| {
                        self.sum_input_to_slot(&new_nodes, root_node, time, edge.from_slot(), edge.from_ch(), &new_context)
                    })
                },
                // Output = sum of all edges to Null of the same slot & ch, within the given DAG.
                MyNodeData::Graph(ref dag_handle) => {
                    // TODO: we can avoid cloning by reversing the push after recursing.
                    let mut new_context = context.clone();
                    new_context.push((nodes, from));
                    let subdag = &nodes[&NodeHandle::new_dag(dag_handle.clone())];
                    self.sum_input_to_slot(nodes, &subdag, time, edge.from_slot(), edge.from_ch(), &new_context)
                }
                // Output = sum of all inputs to slot 0 of the same ch.
                MyNodeData::Delay(ref frames) => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 0 {
                        println!("Warning: attempt to read from Delay slot != 0");
                        0f64
                    } else {
                        // t<0 -> value is 0.
                        time.checked_sub(*frames).map_or(0f64, |origin_time| {
                            self.sum_input_to_slot(nodes, node, origin_time, 0, edge.from_ch(), context)
                        })
                    }
                },
                MyNodeData::Constant(ref value) => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 0 {
                        println!("Warning: attempt to read from Constant slot != 0");
                        0f64
                    } else {
                        *value as f64
                    }
                },
                MyNodeData::Multiply => {
                    // The only nonzero output is slot=1.
                    if edge.from_slot() != 0 {
                        println!("Warning: attempt to read from Multiply slot != 0");
                        0f64
                    } else {
                        // Sum all inputs from slot=0 and slot=2 into two separate
                        // variables, then multiply them.
                        let val_a = self.sum_input_to_slot(nodes, node, time, 0, edge.from_ch(), context);
                        let val_b = self.sum_input_to_slot(nodes, node, time, 1, edge.from_ch(), context);
                        val_a * val_b
                    }
                },
                _ => panic!("Internal RefRenderer error: illegal node type"),
            }
        }
    }
    /// Return the sum of all inputs into a specific slot/channel of the given
    /// node at the given time.
    fn sum_input_to_slot(&self, nodes: &NodeMap, node: &Node, time: u64, slot: u32, ch: u8, context: &Vec<(&NodeMap, NodeHandle)>) -> f64 {
        let edges_in = node.inbound.iter().filter(|in_edge| {
            in_edge.to_slot() == slot && in_edge.to_ch() == ch
        });
        edges_in.map(|edge| self.get_value(nodes, edge, time, context)).sum()
    }

    fn make_node(&self, data: &NodeData) -> MyNodeData {
        match *data {
            NodeData::Graph(ref handle) => MyNodeData::Graph(handle.clone()),
            NodeData::Effect(ref effect) => {
                match effect.meta().get_primitive_url() {
                    Some(ref url) => {
                        let mut params: HashMap<_, _> = url.query_pairs().collect();
                        match url.path() {
                            "/Delay" => {
                                let frames: u64 = match params.entry(Cow::from("frames")) {
                                    hash_map::Entry::Occupied(e) => e.remove().parse().unwrap(),
                                    hash_map::Entry::Vacant(_) => 0u64,
                                };
                                // Make sure we consumed all arguments.
                                assert!(params.is_empty());
                                MyNodeData::Delay(frames)
                            },
                            "/Constant" => {
                                let value: f32 = match params.entry(Cow::from("value")) {
                                    hash_map::Entry::Occupied(e) => e.remove().parse().unwrap(),
                                    hash_map::Entry::Vacant(_) => 0f32,
                                };
                                // Make sure we consumed all arguments.
                                assert!(params.is_empty());
                                MyNodeData::Constant(value)
                            },
                            "/Multiply" => MyNodeData::Multiply,
                            _ => panic!("Unrecognized primitive effect: {} (full url: {})", url.path(), url),
                        }
                    }
                    None => {
                        let graph = effect.routegraph().as_ref().unwrap();
                        let mut nodes = HashMap::new();
                        for (node, data) in graph.iter_nodes() {
                            nodes.insert(node.clone(), Node::new(self.make_node(data)));
                        }
                        for edge in graph.iter_edges() {
                            nodes.entry(edge.to_full()).or_insert_with(|| {
                                Node::new(MyNodeData::DagIO)
                            }).inbound.insert(edge.clone());
                        }
                        MyNodeData::UserNode(nodes)
                    }
                }
            }
        }
    }
}

impl GraphWatcher for RefRenderer {
    fn on_add_node(&mut self, handle: &NodeHandle, data: &NodeData) {
        let my_node_data = self.make_node(data);
        self.nodes.insert(handle.clone(), Node::new(my_node_data));
        // If the node is part of a new DAG, allocate data so that future edges
        // to null within the DAG can be held.
        self.nodes.entry(NodeHandle::new_dag(handle.dag_handle().clone())).or_insert_with(|| {
            Node::new(MyNodeData::DagIO)
        });
    }
    fn on_del_node(&mut self, handle: &NodeHandle) {
        self.nodes.remove(handle);
    }
    fn on_add_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.insert(edge.clone());
    }
    fn on_del_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.remove(edge);
    }
}

impl Node {
    fn new(data: MyNodeData) -> Self {
        Node {
            data: data,
            inbound: HashSet::new(),
        }
    }
}
<commit_msg>Implement multiplicative inverse and modulo by one<commit_after>use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::collections::hash_map;

use render::Renderer;
use routing::{DagHandle, Edge, GraphWatcher, NodeData, NodeHandle};

type NodeMap = HashMap<NodeHandle, Node>;

#[derive(Default)]
pub struct RefRenderer {
    nodes: NodeMap,
}

struct Node {
    data: MyNodeData,
    inbound: HashSet<Edge>
}

enum MyNodeData {
    /// This node is a non-primitive effect.
    UserNode(NodeMap),
    /// This node is an instance of another DAG.
    Graph(DagHandle),
    /// Primitive Delay(samples) effect
    Delay(u64),
    /// Primitive Constant(value) effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    Constant(f32),
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate 1/A
    MultInv,
    /// Primitive effect to calculate A%1 (i.e. A - A.floor())
    ModuloOne,
    /// This node is a DAG definition. i.e. it holds the output edges of a DAG.
    DagIO,
}

impl Renderer for RefRenderer {
    fn get_sample(&mut self, time: u64, ch: u8) -> f32 {
        // Try to find the edge that goes to -> (Null, slot=0, ch=ch)
        let root_handle = NodeHandle::toplevel();
        // empty graph is 0 = silence
        self.nodes.get(&root_handle).map_or(0f32, |node| {
            // find all edges to ([Null], slot=0, ch=ch)
            self.sum_input_to_slot(&self.nodes, node, time, 0, ch, &Vec::new()) as f32
        })
    }
}
impl RefRenderer {
    /// Get the value on an edge at a particular time
    /// When backtracking from the output, we push each Node onto the context if we enter inside of
    ///   it (i.e. if it's a nested DAG) & pop when exiting.
    fn get_value(&self, nodes: &NodeMap, edge: &Edge, time: u64, context: &Vec<(&NodeMap, NodeHandle)>) -> f64 {
        let from = edge.from_full();
        if *from.node_handle() == None {
            // Reading from one of the inputs to the top of `context`
            // TODO: we can avoid cloning by reversing the pop after recursing.
            let mut new_context = context.clone();
            let (new_nodes, head) = new_context.pop().unwrap();
            // Sum the inputs to the matching slot/ch
            self.sum_input_to_slot(new_nodes, &new_nodes[&head], time, edge.from_slot(), edge.from_ch(), &new_context)
        } else {
            // Reading from another node within the DAG
            let node = &nodes[&from];
            match node.data {
                MyNodeData::UserNode(ref new_nodes) => {
                    let mut new_context = context.clone();
                    new_context.push((nodes, from));
                    // Now find the *output* of the sub dag (or 0 if the sub dag has no outputs)
                    new_nodes.get(&NodeHandle::toplevel()).map_or(0f64, |root_node| {
                        self.sum_input_to_slot(&new_nodes, root_node, time, edge.from_slot(), edge.from_ch(), &new_context)
                    })
                },
                // Output = sum of all edges to Null of the same slot & ch, within the given DAG.
                MyNodeData::Graph(ref dag_handle) => {
                    // TODO: we can avoid cloning by reversing the push after recursing.
                    let mut new_context = context.clone();
                    new_context.push((nodes, from));
                    let subdag = &nodes[&NodeHandle::new_dag(dag_handle.clone())];
                    self.sum_input_to_slot(nodes, &subdag, time, edge.from_slot(), edge.from_ch(), &new_context)
                }
                // Output = sum of all inputs to slot 0 of the same ch.
                MyNodeData::Delay(ref frames) => {
                    // The only nonzero output is slot=0.
                    if edge.from_slot() != 0 {
                        println!("Warning: attempt to read from Delay slot != 0");
                        0f64
                    } else {
                        // t<0 -> value is 0.
                        time.checked_sub(*frames).map_or(0f64, |origin_time| {
                            self.sum_input_to_slot(nodes, node, origin_time, 0, edge.from_ch(), context)
                        })
                    }
                },
                MyNodeData::Constant(ref value) => {
                    // The only nonzero output is slot=0.
                    if edge.from_slot() != 0 {
                        println!("Warning: attempt to read from Constant slot != 0");
                        0f64
                    } else {
                        *value as f64
                    }
                },
                MyNodeData::Multiply => {
                    // The only nonzero output is slot=0.
                    if edge.from_slot() != 0 {
                        println!("Warning: attempt to read from Multiply slot != 0");
                        0f64
                    } else {
                        // Sum all inputs from slot=0 and slot=2 into two separate
                        // variables, then multiply them.
                        let val_a = self.sum_input_to_slot(nodes, node, time, 0, edge.from_ch(), context);
                        let val_b = self.sum_input_to_slot(nodes, node, time, 1, edge.from_ch(), context);
                        val_a * val_b
                    }
                },
                MyNodeData::MultInv => {
                    // The only nonzero output is slot=0.
                    if edge.from_slot() != 0 {
                        println!("Warning: attempt to read from MultInv slot != 0");
                        0f64
                    } else {
                        // Sum all inputs
                        let val_in = self.sum_input_to_slot(nodes, node, time, 0, edge.from_ch(), context);
                        1.0f64 / val_in
                    }
                },
                MyNodeData::ModuloOne => {
                    // The only nonzero output is slot=0.
                    if edge.from_slot() != 0 {
                        println!("Warning: attempt to read from ModOne slot != 0");
                        0f64
                    } else {
                        // Sum all inputs
                        let val_in = self.sum_input_to_slot(nodes, node, time, 0, edge.from_ch(), context);
                        //val_in - val_in.floor()
                        // avoid subtracting unbounded numbers: approximate modulus via this:
                        let rem = val_in.fract();
                        if rem < 0f64 {
                            // TODO: We may be losing precision here, if rem is small.
                            // We should find a way to do true modulus.
                            rem + 1.0f64
                        } else {
                            rem
                        }
                    }
                },
                _ => panic!("Internal RefRenderer error: illegal node type"),
            }
        }
    }
    /// Return the sum of all inputs into a specific slot/channel of the given
    /// node at the given time.
    fn sum_input_to_slot(&self, nodes: &NodeMap, node: &Node, time: u64, slot: u32, ch: u8, context: &Vec<(&NodeMap, NodeHandle)>) -> f64 {
        let edges_in = node.inbound.iter().filter(|in_edge| {
            in_edge.to_slot() == slot && in_edge.to_ch() == ch
        });
        edges_in.map(|edge| self.get_value(nodes, edge, time, context)).sum()
    }

    fn make_node(&self, data: &NodeData) -> MyNodeData {
        match *data {
            NodeData::Graph(ref handle) => MyNodeData::Graph(handle.clone()),
            NodeData::Effect(ref effect) => {
                match effect.meta().get_primitive_url() {
                    Some(ref url) => {
                        let mut params: HashMap<_, _> = url.query_pairs().collect();
                        match url.path() {
                            "/Delay" => {
                                let frames: u64 = match params.entry(Cow::from("frames")) {
                                    hash_map::Entry::Occupied(e) => e.remove().parse().unwrap(),
                                    hash_map::Entry::Vacant(_) => 0u64,
                                };
                                // Make sure we consumed all arguments.
                                assert!(params.is_empty());
                                MyNodeData::Delay(frames)
                            },
                            "/Constant" => {
                                let value: f32 = match params.entry(Cow::from("value")) {
                                    hash_map::Entry::Occupied(e) => e.remove().parse().unwrap(),
                                    hash_map::Entry::Vacant(_) => 0f32,
                                };
                                // Make sure we consumed all arguments.
                                assert!(params.is_empty());
                                MyNodeData::Constant(value)
                            },
                            "/Multiply" => MyNodeData::Multiply,
                            "/MultInv" => MyNodeData::MultInv,
                            "/ModuloOne" => MyNodeData::ModuloOne,
                            _ => panic!("Unrecognized primitive effect: {} (full url: {})", url.path(), url),
                        }
                    }
                    None => {
                        let graph = effect.routegraph().as_ref().unwrap();
                        let mut nodes = HashMap::new();
                        for (node, data) in graph.iter_nodes() {
                            nodes.insert(node.clone(), Node::new(self.make_node(data)));
                        }
                        for edge in graph.iter_edges() {
                            nodes.entry(edge.to_full()).or_insert_with(|| {
                                Node::new(MyNodeData::DagIO)
                            }).inbound.insert(edge.clone());
                        }
                        MyNodeData::UserNode(nodes)
                    }
                }
            }
        }
    }
}

impl GraphWatcher for RefRenderer {
    fn on_add_node(&mut self, handle: &NodeHandle, data: &NodeData) {
        let my_node_data = self.make_node(data);
        self.nodes.insert(handle.clone(), Node::new(my_node_data));
        // If the node is part of a new DAG, allocate data so that future edges
        // to null within the DAG can be held.
        self.nodes.entry(NodeHandle::new_dag(handle.dag_handle().clone())).or_insert_with(|| {
            Node::new(MyNodeData::DagIO)
        });
    }
    fn on_del_node(&mut self, handle: &NodeHandle) {
        self.nodes.remove(handle);
    }
    fn on_add_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.insert(edge.clone());
    }
    fn on_del_edge(&mut self, edge: &Edge) {
        self.nodes.get_mut(&edge.to_full()).unwrap().inbound.remove(edge);
    }
}

impl Node {
    fn new(data: MyNodeData) -> Self {
        Node {
            data: data,
            inbound: HashSet::new(),
        }
    }
}
<|endoftext|>