<commit_before>extern crate ransid;

use std::cmp;
use std::collections::{BTreeSet, VecDeque};
use std::io::Result;

use orbclient::{Color, Event, EventOption, Renderer, Window, WindowFlag};
use orbfont::Font;

#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
    asm!("cld
        rep movsq"
        :
        : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
        : "cc", "memory", "rdi", "rsi", "rcx"
        : "intel", "volatile");
}

#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
    asm!("cld
        rep stosq"
        :
        : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
        : "cc", "memory", "rdi", "rcx"
        : "intel", "volatile");
}

pub struct Console {
    pub console: ransid::Console,
    pub window: Window,
    pub font: Font,
    pub font_bold: Font,
    pub changed: BTreeSet<usize>,
    pub ctrl: bool,
    pub input: Vec<u8>,
    pub end_of_input: bool,
    pub cooked: VecDeque<u8>,
    pub requested: usize
}

impl Console {
    pub fn new(width: u32, height: u32) -> Console {
        let mut window = Window::new_flags(-1, -1, width, height, "Terminal", &[WindowFlag::Async]).unwrap();
        window.sync();
        Console {
            console: ransid::Console::new(width as usize / 8, height as usize / 16),
            window: window,
            font: Font::find(None, None, None).unwrap(),
            font_bold: Font::find(None, None, Some("Bold")).unwrap(),
            changed: BTreeSet::new(),
            ctrl: false,
            input: Vec::new(),
            end_of_input: false,
            cooked: VecDeque::new(),
            requested: 0
        }
    }

    pub fn input(&mut self, event: &Event) {
        match event.to_option() {
            EventOption::Key(key_event) => {
                let mut buf = vec![];

                if key_event.scancode == 0x1D {
                    self.ctrl = key_event.pressed;
                } else if key_event.pressed {
                    match key_event.scancode {
                        0x0E => { // Backspace
                            buf.extend_from_slice(b"\x7F");
                        },
                        0x1C => { // Enter
                            buf.extend_from_slice(b"\r");
                        }
                        0x47 => { // Home
                            buf.extend_from_slice(b"\x1B[H");
                        },
                        0x48 => { // Up
                            buf.extend_from_slice(b"\x1B[A");
                        },
                        0x49 => { // Page up
                            buf.extend_from_slice(b"\x1B[5~");
                        },
                        0x4B => { // Left
                            buf.extend_from_slice(b"\x1B[D");
                        },
                        0x4D => { // Right
                            buf.extend_from_slice(b"\x1B[C");
                        },
                        0x4F => { // End
                            buf.extend_from_slice(b"\x1B[F");
                        },
                        0x50 => { // Down
                            buf.extend_from_slice(b"\x1B[B");
                        },
                        0x51 => { // Page down
                            buf.extend_from_slice(b"\x1B[6~");
                        },
                        0x52 => { // Insert
                            buf.extend_from_slice(b"\x1B[2~");
                        },
                        0x53 => { // Delete
                            buf.extend_from_slice(b"\x1B[3~");
                        },
                        _ => {
                            let c = match key_event.character {
                                c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
                                c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
                                c => c
                            };

                            if c != '\0' {
                                buf.extend_from_slice(&[c as u8]);
                            }
                        }
                    }
                }

                if self.console.raw_mode {
                    for &b in buf.iter() {
                        self.input.push(b);
                    }
                } else {
                    for &b in buf.iter() {
                        match b {
                            b'\x03' => {
                                self.end_of_input = true;
                                let _ = self.write(b"^C\n", true);
                            },
                            b'\x08' | b'\x7F' => {
                                if let Some(_c) = self.cooked.pop_back() {
                                    let _ = self.write(b"\x08", true);
                                }
                            },
                            b'\x1B' => {
                                let _ = self.write(b"^[", true);
                            },
                            b'\n' | b'\r' => {
                                self.cooked.push_back(b);
                                while let Some(c) = self.cooked.pop_front() {
                                    self.input.push(c);
                                }
                                let _ = self.write(b"\n", true);
                            },
                            _ => {
                                self.cooked.push_back(b);
                                let _ = self.write(&[b], true);
                            }
                        }
                    }
                }
            },
            _ => () //TODO: Mouse in terminal
        }
    }

    pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) {
        let width = self.window.width() as usize;
        let height = self.window.height() as usize;

        let start_y = cmp::min(height - 1, y);
        let end_y = cmp::min(height, y + h);

        let start_x = cmp::min(width - 1, x);
        let len = cmp::min(width, x + w) - start_x;

        let mut offscreen_ptr = self.window.data_mut().as_mut_ptr() as usize;

        let stride = width * 4;

        let offset = y * stride + start_x * 4;
        offscreen_ptr += offset;

        let mut rows = end_y - start_y;
        while rows > 0 {
            let mut row_ptr = offscreen_ptr;
            let mut cols = len;
            while cols > 0 {
                unsafe {
                    let color = *(row_ptr as *mut u32);
                    *(row_ptr as *mut u32) = color ^ 0x00FFFFFF;
                }
                row_ptr += 4;
                cols -= 1;
            }
            offscreen_ptr += stride;
            rows -= 1;
        }
    }

    pub fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
        if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
            let x = self.console.x;
            let y = self.console.y;
            self.invert(x * 8, y * 16, 8, 16);
            self.changed.insert(y);
        }

        {
            let font = &self.font;
            let font_bold = &self.font_bold;
            let window = &mut self.window;
            let changed = &mut self.changed;
            self.console.write(buf, |event| {
                match event {
                    ransid::Event::Char { x, y, c, color, bold, .. } => {
                        if bold {
                            font_bold.render(&c.to_string(), 16.0).draw(window, x as i32 * 8, y as i32 * 16, Color { data: color.data });
                        } else {
                            font.render(&c.to_string(), 16.0).draw(window, x as i32 * 8, y as i32 * 16, Color { data: color.data });
                        }
                        changed.insert(y);
                    },
                    ransid::Event::Rect { x, y, w, h, color } => {
                        window.rect(x as i32 * 8, y as i32 * 16, w as u32 * 8, h as u32 * 16, Color { data: color.data });
                        for y2 in y..y + h {
                            changed.insert(y2);
                        }
                    },
                    ransid::Event::Scroll { rows, color } => {
                        let rows = rows as u32 * 16;
                        let data = (color.data as u64) << 32 | color.data as u64;

                        let width = window.width()/2;
                        let height = window.height();
                        if rows > 0 && rows < height {
                            let off1 = rows * width;
                            let off2 = height * width - off1;
                            unsafe {
                                let data_ptr = window.data_mut().as_mut_ptr() as *mut u64;
                                fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2 as usize);
                                fast_set64(data_ptr.offset(off2 as isize), data, off1 as usize);
                            }
                        }

                        for y in 0..window.height()/16 {
                            changed.insert(y as usize);
                        }
                    }
                }
            });
        }

        if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
            let x = self.console.x;
            let y = self.console.y;
            self.invert(x * 8, y * 16, 8, 16);
            self.changed.insert(y as usize);
        }

        if ! self.console.raw_mode && sync {
            self.sync();
        }

        Ok(buf.len())
    }

    fn sync(&mut self) {
        /*
        let width = self.window.width;
        for change in self.changed.iter() {
            self.display.sync(0, change * 16, width, 16);
        }
        */
        if ! self.changed.is_empty() {
            self.window.sync();
        }
        self.changed.clear();
    }

    pub fn redraw(&mut self) {
        /*
        let width = self.window.width;
        let height = self.window.height;
        */
        self.window.sync();
        self.changed.clear();
    }
}
<commit_msg>Improve performance of character rendering<commit_after>extern crate ransid;

use std::cmp;
use std::collections::{BTreeSet, VecDeque};
use std::io::Result;

use orbclient::{Color, Event, EventOption, Renderer, Window, WindowFlag};
use orbfont::Font;

#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
    asm!("cld
        rep movsq"
        :
        : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
        : "cc", "memory", "rdi", "rsi", "rcx"
        : "intel", "volatile");
}

#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
    asm!("cld
        rep stosq"
        :
        : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
        : "cc", "memory", "rdi", "rcx"
        : "intel", "volatile");
}

pub struct Console {
    pub console: ransid::Console,
    pub window: Window,
    pub font: Font,
    pub font_bold: Font,
    pub changed: BTreeSet<usize>,
    pub ctrl: bool,
    pub input: Vec<u8>,
    pub end_of_input: bool,
    pub cooked: VecDeque<u8>,
    pub requested: usize
}

impl Console {
    pub fn new(width: u32, height: u32) -> Console {
        let mut window = Window::new_flags(-1, -1, width, height, "Terminal", &[WindowFlag::Async]).unwrap();
        window.sync();
        Console {
            console: ransid::Console::new(width as usize / 8, height as usize / 16),
            window: window,
            font: Font::find(None, None, None).unwrap(),
            font_bold: Font::find(None, None, Some("Bold")).unwrap(),
            changed: BTreeSet::new(),
            ctrl: false,
            input: Vec::new(),
            end_of_input: false,
            cooked: VecDeque::new(),
            requested: 0
        }
    }

    pub fn input(&mut self, event: &Event) {
        match event.to_option() {
            EventOption::Key(key_event) => {
                let mut buf = vec![];

                if key_event.scancode == 0x1D {
                    self.ctrl = key_event.pressed;
                } else if key_event.pressed {
                    match key_event.scancode {
                        0x0E => { // Backspace
                            buf.extend_from_slice(b"\x7F");
                        },
                        0x1C => { // Enter
                            buf.extend_from_slice(b"\r");
                        }
                        0x47 => { // Home
                            buf.extend_from_slice(b"\x1B[H");
                        },
                        0x48 => { // Up
                            buf.extend_from_slice(b"\x1B[A");
                        },
                        0x49 => { // Page up
                            buf.extend_from_slice(b"\x1B[5~");
                        },
                        0x4B => { // Left
                            buf.extend_from_slice(b"\x1B[D");
                        },
                        0x4D => { // Right
                            buf.extend_from_slice(b"\x1B[C");
                        },
                        0x4F => { // End
                            buf.extend_from_slice(b"\x1B[F");
                        },
                        0x50 => { // Down
                            buf.extend_from_slice(b"\x1B[B");
                        },
                        0x51 => { // Page down
                            buf.extend_from_slice(b"\x1B[6~");
                        },
                        0x52 => { // Insert
                            buf.extend_from_slice(b"\x1B[2~");
                        },
                        0x53 => { // Delete
                            buf.extend_from_slice(b"\x1B[3~");
                        },
                        _ => {
                            let c = match key_event.character {
                                c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
                                c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
                                c => c
                            };

                            if c != '\0' {
                                buf.extend_from_slice(&[c as u8]);
                            }
                        }
                    }
                }

                if self.console.raw_mode {
                    for &b in buf.iter() {
                        self.input.push(b);
                    }
                } else {
                    for &b in buf.iter() {
                        match b {
                            b'\x03' => {
                                self.end_of_input = true;
                                let _ = self.write(b"^C\n", true);
                            },
                            b'\x08' | b'\x7F' => {
                                if let Some(_c) = self.cooked.pop_back() {
                                    let _ = self.write(b"\x08", true);
                                }
                            },
                            b'\x1B' => {
                                let _ = self.write(b"^[", true);
                            },
                            b'\n' | b'\r' => {
                                self.cooked.push_back(b);
                                while let Some(c) = self.cooked.pop_front() {
                                    self.input.push(c);
                                }
                                let _ = self.write(b"\n", true);
                            },
                            _ => {
                                self.cooked.push_back(b);
                                let _ = self.write(&[b], true);
                            }
                        }
                    }
                }
            },
            _ => () //TODO: Mouse in terminal
        }
    }

    pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) {
        let width = self.window.width() as usize;
        let height = self.window.height() as usize;

        let start_y = cmp::min(height - 1, y);
        let end_y = cmp::min(height, y + h);

        let start_x = cmp::min(width - 1, x);
        let len = cmp::min(width, x + w) - start_x;

        let mut offscreen_ptr = self.window.data_mut().as_mut_ptr() as usize;

        let stride = width * 4;

        let offset = y * stride + start_x * 4;
        offscreen_ptr += offset;

        let mut rows = end_y - start_y;
        while rows > 0 {
            let mut row_ptr = offscreen_ptr;
            let mut cols = len;
            while cols > 0 {
                unsafe {
                    let color = *(row_ptr as *mut u32);
                    *(row_ptr as *mut u32) = color ^ 0x00FFFFFF;
                }
                row_ptr += 4;
                cols -= 1;
            }
            offscreen_ptr += stride;
            rows -= 1;
        }
    }

    pub fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
        if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
            let x = self.console.x;
            let y = self.console.y;
            self.invert(x * 8, y * 16, 8, 16);
            self.changed.insert(y);
        }

        {
            let font = &self.font;
            let font_bold = &self.font_bold;
            let window = &mut self.window;
            let changed = &mut self.changed;
            let mut str_buf = [0; 4];
            self.console.write(buf, |event| {
                match event {
                    ransid::Event::Char { x, y, c, color, bold, .. } => {
                        if bold {
                            font_bold.render(&c.encode_utf8(&mut str_buf), 16.0).draw(window, x as i32 * 8, y as i32 * 16, Color { data: color.data });
                        } else {
                            font.render(&c.encode_utf8(&mut str_buf), 16.0).draw(window, x as i32 * 8, y as i32 * 16, Color { data: color.data });
                        }
                        changed.insert(y);
                    },
                    ransid::Event::Rect { x, y, w, h, color } => {
                        window.rect(x as i32 * 8, y as i32 * 16, w as u32 * 8, h as u32 * 16, Color { data: color.data });
                        for y2 in y..y + h {
                            changed.insert(y2);
                        }
                    },
                    ransid::Event::Scroll { rows, color } => {
                        let rows = rows as u32 * 16;
                        let data = (color.data as u64) << 32 | color.data as u64;

                        let width = window.width()/2;
                        let height = window.height();
                        if rows > 0 && rows < height {
                            let off1 = rows * width;
                            let off2 = height * width - off1;
                            unsafe {
                                let data_ptr = window.data_mut().as_mut_ptr() as *mut u64;
                                fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2 as usize);
                                fast_set64(data_ptr.offset(off2 as isize), data, off1 as usize);
                            }
                        }

                        for y in 0..window.height()/16 {
                            changed.insert(y as usize);
                        }
                    }
                }
            });
        }

        if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
            let x = self.console.x;
            let y = self.console.y;
            self.invert(x * 8, y * 16, 8, 16);
            self.changed.insert(y as usize);
        }

        if ! self.console.raw_mode && sync {
            self.sync();
        }

        Ok(buf.len())
    }

    fn sync(&mut self) {
        /*
        let width = self.window.width;
        for change in self.changed.iter() {
            self.display.sync(0, change * 16, width, 16);
        }
        */
        if ! self.changed.is_empty() {
            self.window.sync();
        }
        self.changed.clear();
    }

    pub fn redraw(&mut self) {
        /*
        let width = self.window.width;
        let height = self.window.height;
        */
        self.window.sync();
        self.changed.clear();
    }
}
<|endoftext|>


<commit_before>use base::{AbstractCFType, CFAllocatorRef, CFIndex, CFRelease, CFTypeRef, kCFAllocatorDefault};
use dvec::DVec;
use libc::c_void;
use ptr::to_unsafe_ptr;
use unsafe::reinterpret_cast;
use vec::unsafe::to_ptr;

pub type CFDictionaryRetainCallBack = *u8;
pub type CFDictionaryReleaseCallBack = *u8;
pub type CFDictionaryCopyDescriptionCallBack = *u8;
pub type CFDictionaryEqualCallBack = *u8;
pub type CFDictionaryHashCallBack = *u8;

pub struct CFDictionaryKeyCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack,
    hash: CFDictionaryHashCallBack
}

pub struct CFDictionaryValueCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack
}

struct __CFDictionary { private: () }
pub type CFDictionaryRef = *__CFDictionary;

struct CFDictionary<K:AbstractCFType,V:AbstractCFType> {
    obj: CFDictionaryRef,

    drop {
        unsafe {
            CFRelease(reinterpret_cast(&self.obj));
        }
    }
}

mod CFDictionary {
    fn wrap<K:AbstractCFType,V:AbstractCFType>(obj: CFDictionaryRef) -> CFDictionary<K,V> {
        CFDictionary { obj: obj }
    }

    fn new_dictionary<K:AbstractCFType,V:AbstractCFType>(pairs: &[(K,V)]) -> CFDictionary<K,V> {
        let (keys, values) = (DVec(), DVec());
        for pairs.each |pair| {
            // FIXME: "let" would be much nicer here, but that doesn't work yet.
            match pair {
                (ref key, ref value) => {
                    keys.push(key.as_type_ref());
                    values.push(value.as_type_ref());
                }
            }
        }

        assert keys.len() == values.len();
        let keys = vec::from_mut(dvec::unwrap(keys));
        let values = vec::from_mut(dvec::unwrap(values));

        let dictionary_ref;
        unsafe {
            dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault,
                                                reinterpret_cast(&to_ptr(keys)),
                                                reinterpret_cast(&to_ptr(values)),
                                                keys.len() as CFIndex,
                                                to_unsafe_ptr(&kCFTypeDictionaryKeyCallBacks),
                                                to_unsafe_ptr(&kCFTypeDictionaryValueCallBacks));
        }

        return wrap(dictionary_ref);
    }
}

impl<K:AbstractCFType,V:AbstractCFType> CFDictionary<K,V> : AbstractCFType {
    pure fn as_type_ref(&self) -> CFTypeRef {
        unsafe {
            reinterpret_cast(&self.obj)
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    const kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks;
    const kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks;

    fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: **c_void, values: **c_void,
                          numValues: CFIndex, keyCallBacks: *CFDictionaryKeyCallBacks,
                          valueCallBacks: *CFDictionaryValueCallBacks)
                       -> CFDictionaryRef;
}

<commit_msg>Fixes for language changes<commit_after>use base::{AbstractCFType, CFAllocatorRef, CFIndex, CFRelease, CFTypeRef, kCFAllocatorDefault};
use dvec::DVec;
use libc::c_void;
use ptr::to_unsafe_ptr;
use unsafe::reinterpret_cast;
use vec::raw::to_ptr;

pub type CFDictionaryRetainCallBack = *u8;
pub type CFDictionaryReleaseCallBack = *u8;
pub type CFDictionaryCopyDescriptionCallBack = *u8;
pub type CFDictionaryEqualCallBack = *u8;
pub type CFDictionaryHashCallBack = *u8;

pub struct CFDictionaryKeyCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack,
    hash: CFDictionaryHashCallBack
}

pub struct CFDictionaryValueCallBacks {
    version: CFIndex,
    retain: CFDictionaryRetainCallBack,
    release: CFDictionaryReleaseCallBack,
    copyDescription: CFDictionaryCopyDescriptionCallBack,
    equal: CFDictionaryEqualCallBack
}

struct __CFDictionary { private: () }
pub type CFDictionaryRef = *__CFDictionary;

struct CFDictionary<K:AbstractCFType,V:AbstractCFType> {
    obj: CFDictionaryRef,

    drop {
        unsafe {
            CFRelease(reinterpret_cast(&self.obj));
        }
    }
}

mod CFDictionary {
    fn wrap<K:AbstractCFType,V:AbstractCFType>(obj: CFDictionaryRef) -> CFDictionary<K,V> {
        CFDictionary { obj: obj }
    }

    fn new_dictionary<K:AbstractCFType,V:AbstractCFType>(pairs: &[(K,V)]) -> CFDictionary<K,V> {
        let (keys, values) = (DVec(), DVec());
        for pairs.each |pair| {
            // FIXME: "let" would be much nicer here, but that doesn't work yet.
            match pair {
                (ref key, ref value) => {
                    keys.push(key.as_type_ref());
                    values.push(value.as_type_ref());
                }
            }
        }

        assert keys.len() == values.len();
        let keys = dvec::unwrap(keys);
        let values = dvec::unwrap(values);

        let dictionary_ref;
        unsafe {
            dictionary_ref = CFDictionaryCreate(kCFAllocatorDefault,
                                                reinterpret_cast(&to_ptr(keys)),
                                                reinterpret_cast(&to_ptr(values)),
                                                keys.len() as CFIndex,
                                                to_unsafe_ptr(&kCFTypeDictionaryKeyCallBacks),
                                                to_unsafe_ptr(&kCFTypeDictionaryValueCallBacks));
        }

        return wrap(dictionary_ref);
    }
}

impl<K:AbstractCFType,V:AbstractCFType> CFDictionary<K,V> : AbstractCFType {
    pure fn as_type_ref(&self) -> CFTypeRef {
        unsafe {
            reinterpret_cast(&self.obj)
        }
    }
}

#[link_args="-framework CoreFoundation"]
#[nolink]
extern {
    const kCFTypeDictionaryKeyCallBacks: CFDictionaryKeyCallBacks;
    const kCFTypeDictionaryValueCallBacks: CFDictionaryValueCallBacks;

    fn CFDictionaryCreate(allocator: CFAllocatorRef, keys: **c_void, values: **c_void,
                          numValues: CFIndex, keyCallBacks: *CFDictionaryKeyCallBacks,
                          valueCallBacks: *CFDictionaryValueCallBacks)
                       -> CFDictionaryRef;
}

<|endoftext|>


<commit_before>use super::Topic;

pub struct Elementary;

impl Topic for Elementary {

    fn run_example(&self, n: u8) {

        println!("Input was: {}", n);
    }

    fn describe(&self) -> String { "elementary".to_string() }
}
<commit_msg>EM: skeleton of example 2<commit_after>use super::Topic;

pub struct Elementary;

impl Topic for Elementary {

    fn run_example(&self, n: u8) {

        println!("Topic: Elementary, example {}", n);
        match n {
            1 => { println!("Hello, world!"); },
            2 => { example_2(); },
            _ => { println!("Example not known or not implemented!"); }
        };
    }

    fn describe(&self) -> String { "elementary".to_string() }
}

fn example_2() {
    println!("Todo");
        // TODO
}
<|endoftext|>


<commit_before>//! Useful stuff related to the spaceapi.

/// An ``Optional`` can contain ``Optional::Value<T>`` or ``Optional::Absent``.
/// It is similar to an ``Option``, but ``Optional::Absent`` means it will be
/// omitted when serialized, while ``None`` will be serialized to ``null``.
#[derive(Debug, Copy, Clone)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

}
<commit_msg>spaceapi: Add `is_absent` to `Optional`<commit_after>//! Useful stuff related to the spaceapi.

/// An ``Optional`` can contain ``Optional::Value<T>`` or ``Optional::Absent``.
/// It is similar to an ``Option``, but ``Optional::Absent`` means it will be
/// omitted when serialized, while ``None`` will be serialized to ``null``.
#[derive(Debug, Copy, Clone)]
pub enum Optional<T> {
    Value(T),
    Absent,
}

impl<T> Optional<T> {

    /// Applies a function to the contained value or returns a default.  see
    /// [`std::option::Option<T>::map_or`](http://doc.rust-lang.org/std/option/enum.Option.html#method.map_or)
    pub fn map_or<U, F: FnOnce(T) -> U>(self, def: U, f: F) -> U {
        match self {
            Optional::Value(v) => f(v),
            Optional::Absent => def,
        }
    }

    pub fn as_mut<'r>(&'r mut self) -> Optional<&'r mut T> {
        match *self {
            Optional::Value(ref mut x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    pub fn as_ref<'r>(&'r self) -> Optional<&'r T> {
        match *self {
            Optional::Value(ref x) => Optional::Value(x),
            Optional::Absent => Optional::Absent
        }
    }

    pub fn is_absent(&self) -> bool {
        match *self {
            Optional::Absent => true,
            _ => false
        }
    }

}
<|endoftext|>


<commit_before>extern crate log;
extern crate time;

use std::error::Error;
use std::fs::File;
use std::path::Path;
use std::io::Write;
use std::fmt;

use std::sync::{Mutex};

use log::{LogRecord, LogLevel, LogLevelFilter, SetLoggerError, LogMetadata};
use time::{Tm};

fn timestamp() -> String{
    let now = time::now();
    let mut time_string = match time::strftime("%F %T", &now){
                            Ok(S) => S,
                            Err(_) => "".to_string(),
    };

    let milli_string = now.tm_nsec /1000 /1000;

    let timestamp = fmt::format(format_args!("{}.{:03}", time_string,  milli_string));

    return timestamp;
}

pub struct SimpleFileLogger {
    logfile: Mutex<Option<File>>,
}

impl log::Log for SimpleFileLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {

            let mut buffer = Vec::new();
            write!(&mut buffer, "{} - {} - {}\n", timestamp(), record.level(), record.args());

            let mut file = self.logfile.lock().unwrap();

            match *file {
                Some(ref mut file) => {
                    match file.write(buffer.as_slice()) {
                        Err(why) => panic!("couldn't write: {}", Error::description(&why)),
                        Ok(_) => (),
                    }
                }
                None => panic!("logfile does not exist!"),
            };
        }
    }
}

impl SimpleFileLogger {
    pub fn init() -> Result<(), SetLoggerError> {

        let path = Path::new("trace.log");
        let display = path.display();

        // Open a file in write-only mode, returns `io::Result<File>`
        let file = match File::create(&path) {
            Err(why) => panic!("couldn't create {}: {}", display, Error::description(&why)),
            Ok(file) => file,
        };

        log::set_logger(|max_log_level| {
            max_log_level.set(LogLevelFilter::Info);
            Box::new(SimpleFileLogger {
                logfile: Mutex::new(Some(file))
            })
        })
    }

}
<commit_msg>fix some warnings<commit_after>extern crate log;
extern crate time;

use std::error::Error;
use std::fs::File;
use std::path::Path;
use std::io::Write;
use std::fmt;

use std::sync::{Mutex};

use log::{LogRecord, LogLevel, LogLevelFilter, SetLoggerError, LogMetadata};

fn timestamp() -> String{
    let now = time::now();
    let time_string = match time::strftime("%F %T", &now){
                            Ok(s) => s,
                            Err(_) => "".to_string(),
    };

    let milli_string = now.tm_nsec /1000 /1000;

    let timestamp = fmt::format(format_args!("{}.{:03}", time_string,  milli_string));

    return timestamp;
}

pub struct SimpleFileLogger {
    logfile: Mutex<Option<File>>,
}

impl log::Log for SimpleFileLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {

            let mut buffer = Vec::new();
            write!(&mut buffer, "{} - {} - {}\n", timestamp(), record.level(), record.args());

            let mut file = self.logfile.lock().unwrap();

            match *file {
                Some(ref mut file) => {
                    match file.write(buffer.as_slice()) {
                        Err(why) => panic!("couldn't write: {}", Error::description(&why)),
                        Ok(_) => (),
                    }
                }
                None => panic!("logfile does not exist!"),
            };
        }
    }
}

impl SimpleFileLogger {
    pub fn init() -> Result<(), SetLoggerError> {

        let path = Path::new("trace.log");
        let display = path.display();

        // Open a file in write-only mode, returns `io::Result<File>`
        let file = match File::create(&path) {
            Err(why) => panic!("couldn't create {}: {}", display, Error::description(&why)),
            Ok(file) => file,
        };

        log::set_logger(|max_log_level| {
            max_log_level.set(LogLevelFilter::Info);
            Box::new(SimpleFileLogger {
                logfile: Mutex::new(Some(file))
            })
        })
    }

}
<|endoftext|>


<commit_before>use std::hash::Hash;
use std::collections::{BTreeMap, HashSet};
use std::cmp::Ordering;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq)]
pub struct VectorClock<S: Ord + Eq + Copy> {
    map: BTreeMap<S, u64>
}

impl <S: Eq + Copy + Ord> PartialOrd for VectorClock<S> {
    fn partial_cmp(&self, other: &VectorClock<S>) -> Option<Ordering> {
        let rel = self.relation(other);
        match rel {
            Relation::Before => Some(Ordering::Less),
            Relation::After => Some(Ordering::Greater),
            Relation::Equal => Some(Ordering::Equal),
            Relation::Concurrent => None
        }
    }

    fn lt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::Before
    }

    fn le(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Before || rel == Relation::Equal
    }

    fn gt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::After
    }

    fn ge(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::After || rel == Relation::Equal
    }
}

impl <S: Eq + Copy + Ord> PartialEq for VectorClock<S> {
    fn eq(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Equal
    }

    fn ne(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        !(rel == Relation::After || rel == Relation::Before)
    }
}

impl <S: Ord + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: BTreeMap::new()
        }
    }

    pub fn inc(&mut self, server: S) -> VectorClock<S> {
        *self.map.entry(server).or_insert(0) += 1;
        self.clone()
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        let mut a_lt_b = false;
        for (server, ai) in self.map.iter() {
            let bi = *clock_b.map.get(server).unwrap_or(&0);
            if *ai > bi {return false;}
            a_lt_b = a_lt_b || *ai < bi;
        }
        for (server, bi) in clock_b.map.iter() {
            let ai = *self.map.get(server).unwrap_or(&0);
            if ai > *bi {return false;}
            a_lt_b = a_lt_b || ai < *bi;
        }
        return a_lt_b;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) -> StandardVectorClock {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &StandardVectorClock) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> StandardVectorClock {
        let clock = self.clock.read();
        clock.clone()
    }
}

pub type StandardVectorClock = VectorClock<u64>;<commit_msg>impl Ord for VectorClock<commit_after>use std::hash::Hash;
use std::collections::{BTreeMap, HashSet};
use std::cmp::Ordering;
use parking_lot::RwLock;
use bifrost_hasher::hash_str;

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub enum Relation {
    Equal,
    Before,
    After,
    Concurrent
}

#[derive(Serialize, Deserialize, Debug, Clone, Hash, Eq)]
pub struct VectorClock<S: Ord + Eq + Copy> {
    map: BTreeMap<S, u64>
}

impl <S: Eq + Copy + Ord> PartialOrd for VectorClock<S> {
    fn partial_cmp(&self, other: &VectorClock<S>) -> Option<Ordering> {
        let rel = self.relation(other);
        match rel {
            Relation::Before => Some(Ordering::Less),
            Relation::After => Some(Ordering::Greater),
            Relation::Equal => Some(Ordering::Equal),
            Relation::Concurrent => None
        }
    }

    fn lt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::Before
    }

    fn le(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Before || rel == Relation::Equal
    }

    fn gt(&self, other: &VectorClock<S>) -> bool {
        self.relation(other) == Relation::After
    }

    fn ge(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::After || rel == Relation::Equal
    }
}

impl <S: Eq + Copy + Ord> Ord for VectorClock<S> {
    fn cmp(&self, other: &Self) -> Ordering {
        let rel = self.relation(other);
        match rel {
            Relation::Before => Ordering::Less,
            Relation::After => Ordering::Greater,
            _ => Ordering::Equal // not justified, but sufficient for BTreeSet data structure
        }
    }
}

impl <S: Eq + Copy + Ord> PartialEq for VectorClock<S> {
    fn eq(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        rel == Relation::Equal
    }

    fn ne(&self, other: &VectorClock<S>) -> bool {
        let rel = self.relation(other);
        !(rel == Relation::After || rel == Relation::Before)
    }
}

impl <S: Ord + Eq + Copy>VectorClock<S> {
    pub fn new() -> VectorClock<S> {
        VectorClock {
            map: BTreeMap::new()
        }
    }

    pub fn inc(&mut self, server: S) -> VectorClock<S> {
        *self.map.entry(server).or_insert(0) += 1;
        self.clone()
    }

    pub fn happened_before(&self, clock_b: &VectorClock<S>) -> bool {
        let mut a_lt_b = false;
        for (server, ai) in self.map.iter() {
            let bi = *clock_b.map.get(server).unwrap_or(&0);
            if *ai > bi {return false;}
            a_lt_b = a_lt_b || *ai < bi;
        }
        for (server, bi) in clock_b.map.iter() {
            let ai = *self.map.get(server).unwrap_or(&0);
            if ai > *bi {return false;}
            a_lt_b = a_lt_b || ai < *bi;
        }
        return a_lt_b;
    }
    pub fn equals(&self, clock_b: &VectorClock<S>) -> bool {
        for (server, ac) in self.map.iter() {
            if let Some(bc) = clock_b.map.get(server) {
                if ac != bc {return false;}
            }
        }
        return true;
    }
    pub fn relation(&self, clock_b: &VectorClock<S>) -> Relation {
        if self.equals(clock_b) {
            return Relation::Equal;
        }
        if self.happened_before(clock_b) {
            return Relation::Before;
        }
        if clock_b.happened_before(self) {
            return Relation::After;
        }
        return Relation::Concurrent;
    }
    pub fn merge_with(&mut self, clock_b: &VectorClock<S>) {
        // merge_with is used to update counter for other servers (also learn from it)
        for (server, bc) in clock_b.map.iter() {
            let mut ba = self.map.entry(*server).or_insert(0);
            if *ba < *bc {*ba = *bc}
        }
    }
    pub fn learn_from(&mut self, clock_b: &VectorClock<S>) {
        // learn_from only insert missing servers into the clock
        for (server, bc) in clock_b.map.iter() {
            self.map.entry(*server).or_insert(*bc);
        }
    }
}

pub struct ServerVectorClock {
    server: u64,
    clock: RwLock<VectorClock<u64>>
}

impl ServerVectorClock {
    pub fn new(server_address: &String) -> ServerVectorClock {
        ServerVectorClock {
            server: hash_str(server_address),
            clock: RwLock::new(VectorClock::new())
        }
    }
    pub fn inc(&self) -> StandardVectorClock {
        let mut clock = self.clock.write();
        clock.inc(self.server)
    }

    pub fn happened_before(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.happened_before(clock_b)
    }
    pub fn equals(&self, clock_b: &StandardVectorClock) -> bool {
        let clock = self.clock.read();
        clock.equals(clock_b)
    }
    pub fn relation(&self, clock_b: &StandardVectorClock) -> Relation {
        let clock = self.clock.read();
        clock.relation(clock_b)
    }
    pub fn merge_with(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.merge_with(clock_b)
    }
    pub fn learn_from(&self, clock_b: &StandardVectorClock) {
        let mut clock = self.clock.write();
        clock.learn_from(clock_b)
    }
    pub fn to_clock(&self) -> StandardVectorClock {
        let clock = self.clock.read();
        clock.clone()
    }
}

pub type StandardVectorClock = VectorClock<u64>;<|endoftext|>


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

//! # Subscription Handlers
//!
//! ## Implementing the Subscription Trait
//! In order to turn a struct containing subscription state into something capable of launching a
//! subscription, you must implement the `Subscription<ParamType, ReturnType>` trait.
//! `ParamType` is what will be used to deserialize JSONRPC Requests
//! `ReturnType` is what will be serialized and sent to the client
//!
//! To implement `Subscription` there are three methods you must define:
//! 1. `init(&mut self, helper: &SubscriptionHelper, params: &ParamType) -> Result<(), JsonRpcError>;`
//!     - This is where initial state is set up to keep track of what has been sent to the client.
//!       This could be any incremental id: a sequence number for events, the transaction version for transactions, etc.
//!     - Returning `Err(JsonRpcRequest)` is the way to handle an issue with a parameter value, or
//!       any other such case where a subscription may not be started or requested data may not be
//!       returned. Otherwise if the parameters are valid and a subscription could be created, simply
//!       return `Ok(())`
//!
//! 2. `next(&self, helper: &SubscriptionHelper, params: &ParamType) -> Vec<ParamType>;`
//!     Within this method, use existing state set up in the `init` function to fetch the next batch of data.
//!     The size of the batch should be determined by `helper.client.config.fetch_size`.
//!     If the function returns an array of data, each item will be serialized one by one and sent to the client.
//!     The `on_send` method (below) will be called for each item in the array.
//!     If the function returns an empty array, the thread will sleep for `client.config.poll_interval_ms`,
//!     increasing exponentially up to a ceiling, and will reset any time the function returns data.
//!
//! 3. `on_send(&mut self, item: &ParamType);`
//!     If the `next` function returns an array of items, after each the item is serialized and sent to the client
//!     it will be passed to this `on_send` method. This is the perfect place to update state fields
//!     which keep track of what has/hasn't been sent to the client.
//!

use crate::{
    errors::JsonRpcError,
    stream_rpc::{connection::ClientConnection, counters},
};
use diem_json_rpc_types::{
    stream::{request::StreamMethod, response::SubscribeResult},
    Id,
};
use diem_logger::debug;
use serde::Serialize;
use std::{iter::Map, sync::Arc, time::Duration};
use storage_interface::DbReader;
use tokio::task::JoinHandle;
use tokio_retry::strategy::ExponentialBackoff;

#[derive(Clone, Debug)]
pub struct SubscriptionConfig {
    pub fetch_size: u64,
    pub poll_interval_ms: u64,
    pub max_poll_interval_ms: u64,
    pub queue_size: usize,
}

type JitterBackoff = Map<ExponentialBackoff, fn(Duration) -> Duration>;

/// Jitter up to 80% of the actual value
pub fn jitter(duration: Duration) -> Duration {
    // Generate a float from 0.8<->1.0
    let jitter = 0.8 + rand::random::<f64>() / 5.0;
    duration.mul_f64(jitter)
}

pub fn create_backoff(poll_interval_ms: u64, max_poll_interval_ms: u64) -> JitterBackoff {
    ExponentialBackoff::from_millis(poll_interval_ms)
        .max_delay(tokio::time::Duration::from_millis(max_poll_interval_ms))
        .map(jitter)
}

#[derive(Clone)]
pub struct SubscriptionHelper {
    pub db: Arc<dyn DbReader>,
    pub client: ClientConnection,
    pub jsonrpc_id: Id,
    pub method: StreamMethod,
    pub backoff: JitterBackoff,
}

impl SubscriptionHelper {
    pub fn new(
        db: Arc<dyn DbReader>,
        client: ClientConnection,
        jsonrpc_id: Id,
        method: StreamMethod,
    ) -> Self {
        let poll_interval_ms = client.config.poll_interval_ms;
        let max_poll_interval_ms = client.config.max_poll_interval_ms;
        Self {
            db,
            client,
            jsonrpc_id,
            method,
            backoff: create_backoff(poll_interval_ms, max_poll_interval_ms),
        }
    }

    /// This is to be one of the first things that a new subscription task must do, to let the client
    /// know that the subscription has been created (some streams may be very sparse, or start with 0 items)
    pub async fn send_ok(&self) {
        counters::SUBSCRIPTION_OKS
            .with_label_values(&[
                self.client.connection_context.transport.as_str(),
                &self.method.as_str(),
                counters::RpcResult::Success.as_str(),
                self.client.connection_context.sdk_info.language.as_str(),
                &self.client.connection_context.sdk_info.version.to_string(),
            ])
            .inc();
        self.client
            .send_success(
                self.jsonrpc_id.clone(),
                &SubscribeResult::ok(self.db.get_latest_version().unwrap_or(0)),
            )
            .await
            .ok();
    }

    pub fn reset_backoff(&mut self) {
        let config = &self.client.config;
        self.backoff = create_backoff(config.poll_interval_ms, config.max_poll_interval_ms);
    }

    pub async fn sleep_wiggled(&mut self) {
        let sleepy_time = self.backoff.next().unwrap();
        debug!(
            "Client#{} Sleeping for {:?}ms as no results for {}",
            self.client.id,
            sleepy_time,
            self.method.as_str()
        );
        tokio::time::sleep(sleepy_time).await;
    }
}

pub trait Subscription<ParamType, ReturnType>: Send + Sync + Clone + Default + 'static
where
    ParamType: Send + Sync + Clone + 'static,
    ReturnType: Send + Sync + Serialize + Clone,
{
    fn init(&mut self, helper: &SubscriptionHelper, params: &ParamType)
        -> Result<(), JsonRpcError>;
    fn next(&self, helper: &SubscriptionHelper, params: &ParamType) -> Vec<ReturnType>;
    fn on_send(&mut self, item: Option<&ReturnType>);

    fn run(
        mut self,
        mut helper: SubscriptionHelper,
        params: ParamType,
    ) -> Result<JoinHandle<()>, JsonRpcError> {
        self.init(&helper, &params)?;

        Ok(tokio::spawn(async move {
            helper.send_ok().await;

            loop {
                let items = self.next(&helper, &params);

                debug!(
                    "Client#{}: fetched {} items for {}",
                    helper.client.id,
                    items.len(),
                    helper.method.as_str()
                );

                if items.is_empty() {
                    self.on_send(None);
                    helper.sleep_wiggled().await;
                    continue;
                }

                helper.reset_backoff();

                counters::SUBSCRIPTION_RPC_SENT
                    .with_label_values(&[
                        helper.client.connection_context.transport.as_str(),
                        helper.method.as_str(),
                        counters::RpcResult::Success.as_str(),
                        helper.client.connection_context.sdk_info.language.as_str(),
                        &helper
                            .client
                            .connection_context
                            .sdk_info
                            .version
                            .to_string(),
                    ])
                    .inc_by(items.len() as u64);

                for item in items {
                    match helper
                        .client
                        .send_success(helper.jsonrpc_id.clone(), &item)
                        .await
                    {
                        Err(e) => {
                            // client has disconnected
                            debug!("Client#{}: Send error: {:?}", &helper.client.id, e);
                            return;
                        }
                        Ok(_) => self.on_send(Some(&item)),
                    };
                }
            }
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        stream_rpc::tests::util::{create_client_connection, timeout},
        tests::utils::MockDiemDB,
    };
    use diem_json_rpc_types::stream::errors::StreamError;
    use serde::{Deserialize, Serialize};
    use std::time::Instant;
    use tokio::sync::mpsc::Receiver;

    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct SubscribeTestParams {
        pub is_valid: bool,
        pub items_to_send: Vec<Vec<TestView>>,
    }

    #[derive(Clone, Copy, Debug, Default)]
    pub struct TestSubscription {
        pub item_index: usize,
    }

    #[derive(Clone, Copy, Debug, Deserialize, Serialize)]
    pub struct TestView {
        pub value: u64,
    }

    impl Subscription<SubscribeTestParams, TestView> for TestSubscription {
        fn init(
            &mut self,
            _helper: &SubscriptionHelper,
            params: &SubscribeTestParams,
        ) -> Result<(), JsonRpcError> {
            // Pretend there's a problem with one of the params
            if params.is_valid {
                Ok(())
            } else {
                Err(JsonRpcError::invalid_param("not is_valid"))
            }
        }

        fn next(
            &self,
            _helper: &SubscriptionHelper,
            params: &SubscribeTestParams,
        ) -> Vec<TestView> {
            let items: Option<&Vec<TestView>> = params.items_to_send.get(self.item_index);
            match items {
                None => vec![],
                Some(items) => items.clone(),
            }
        }

        fn on_send(&mut self, _tx: Option<&TestView>) {
            self.item_index += 1;
        }
    }

    fn create_subscription_helper() -> (
        MockDiemDB,
        ClientConnection,
        Receiver<Result<String, StreamError>>,
        SubscriptionHelper,
    ) {
        let (mock_db, client_connection, receiver) = create_client_connection();

        // The 'method' does not matter for this test (it's used for logging)
        let subscription_helper = SubscriptionHelper::new(
            Arc::new(mock_db.clone()),
            client_connection.clone(),
            Id::Number(1010101),
            StreamMethod::SubscribeToTransactions,
        );

        (mock_db, client_connection, receiver, subscription_helper)
    }

    #[tokio::test]
    async fn test_subscription() {
        let (mock_db, _, mut receiver, subscription_helper) = create_subscription_helper();

        let test_items = vec![
            // Send two items
            vec![TestView { value: 0 }, TestView { value: 1 }],
            // Then don't send anything, and increase the exponential delay
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            // Send some values: the exponential delay should reset
            vec![TestView { value: 2 }],
            vec![TestView { value: 3 }],
        ];

        let params = SubscribeTestParams {
            is_valid: true,
            items_to_send: test_items,
        };

        let handle = TestSubscription::default()
            .run(subscription_helper, params)
            .unwrap();
        let ok_msg = receiver.recv().await;

        let result = ok_msg.unwrap().unwrap();
        let expected = serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result": {"status": "OK", "transaction_version": mock_db.version}}).to_string();
        assert_eq!(expected, result);

        // These should have no delay
        let expected =
            serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result":{"value": 0}}).to_string();
        let next = timeout(10, receiver.recv(), "message 0")
            .await
            .unwrap()
            .unwrap();
        assert_eq!(expected, next);

        let expected =
            serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result":{"value": 1}}).to_string();
        let next = timeout(10, receiver.recv(), "message 1")
            .await
            .unwrap()
            .unwrap();
        assert_eq!(expected, next);

        // Here we have many iterations which return nothing, so the exponential delay should kick in
        let start = Instant::now();
        let expected =
            serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result":{"value": 2}}).to_string();
        let next = timeout(1_000, receiver.recv(), "message 2")
            .await
            .unwrap()
            .unwrap();
        let elapsed = start.elapsed().as_millis();
        assert_eq!(expected, next);
        assert!(elapsed > 500);

        // This one should have no delay again, due to being reset by the previous message
        let expected =
            serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result":{"value": 3}}).to_string();
        let next = timeout(10, receiver.recv(), "message 3")
            .await
            .unwrap()
            .unwrap();
        assert_eq!(expected, next);
        handle.abort();
    }

    #[tokio::test]
    async fn test_init_rejects_subscription() {
        let (_, _, mut receiver, subscription_helper) = create_subscription_helper();

        let params = SubscribeTestParams {
            is_valid: false,
            items_to_send: vec![],
        };

        let handle = TestSubscription::default().run(subscription_helper, params);

        assert!(handle.is_err());
        let expected = serde_json::json!({"code":-32602, "message": "Invalid param not is_valid", "data": null}).to_string();
        assert_eq!(
            expected,
            serde_json::to_string(&handle.err().unwrap()).unwrap()
        );

        // This is expected to be `None` as the client_connection is dropped
        let ok_msg = receiver.recv().await;
        assert!(ok_msg.is_none());
    }

    #[tokio::test]
    async fn test_sleep_jitter_await() {
        let (_, _, _, mut subscription_helper) = create_subscription_helper();

        let mut results = vec![];

        let start = Instant::now();
        let mut last: u64 = 0;

        for _ in 0..10 {
            subscription_helper.sleep_wiggled().await;
            let elapsed = start.elapsed().as_millis() as u64;
            results.push(elapsed - last);
            last = elapsed;
        }

        // In the event the test fails, this println makes it much easier to debug
        println!("jittered sleeps: {:?}", results);

        // 80 Jitter makes exact comparison hard, but exponentially increasing values here should be > 1.8x the previous one
        for i in 5..9 {
            let prev = *results.get(i).unwrap() as f64;
            let curr = *results.get(i + 1).unwrap() as f64 * 1.8;
            assert!(prev < curr);
        }

        subscription_helper.reset_backoff();
        timeout(
            50,
            subscription_helper.sleep_wiggled(),
            "sleep_wiggled after reset_backoff",
        )
        .await;
    }
}
<commit_msg>Fix flakey test_subscription timeouts<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! # Subscription Handlers
//!
//! ## Implementing the Subscription Trait
//! In order to turn a struct containing subscription state into something capable of launching a
//! subscription, you must implement the `Subscription<ParamType, ReturnType>` trait.
//! `ParamType` is what will be used to deserialize JSONRPC Requests
//! `ReturnType` is what will be serialized and sent to the client
//!
//! To implement `Subscription` there are three methods you must define:
//! 1. `init(&mut self, helper: &SubscriptionHelper, params: &ParamType) -> Result<(), JsonRpcError>;`
//!     - This is where initial state is set up to keep track of what has been sent to the client.
//!       This could be any incremental id: a sequence number for events, the transaction version for transactions, etc.
//!     - Returning `Err(JsonRpcRequest)` is the way to handle an issue with a parameter value, or
//!       any other such case where a subscription may not be started or requested data may not be
//!       returned. Otherwise if the parameters are valid and a subscription could be created, simply
//!       return `Ok(())`
//!
//! 2. `next(&self, helper: &SubscriptionHelper, params: &ParamType) -> Vec<ParamType>;`
//!     Within this method, use existing state set up in the `init` function to fetch the next batch of data.
//!     The size of the batch should be determined by `helper.client.config.fetch_size`.
//!     If the function returns an array of data, each item will be serialized one by one and sent to the client.
//!     The `on_send` method (below) will be called for each item in the array.
//!     If the function returns an empty array, the thread will sleep for `client.config.poll_interval_ms`,
//!     increasing exponentially up to a ceiling, and will reset any time the function returns data.
//!
//! 3. `on_send(&mut self, item: &ParamType);`
//!     If the `next` function returns an array of items, after each the item is serialized and sent to the client
//!     it will be passed to this `on_send` method. This is the perfect place to update state fields
//!     which keep track of what has/hasn't been sent to the client.
//!

use crate::{
    errors::JsonRpcError,
    stream_rpc::{connection::ClientConnection, counters},
};
use diem_json_rpc_types::{
    stream::{request::StreamMethod, response::SubscribeResult},
    Id,
};
use diem_logger::debug;
use serde::Serialize;
use std::{iter::Map, sync::Arc, time::Duration};
use storage_interface::DbReader;
use tokio::task::JoinHandle;
use tokio_retry::strategy::ExponentialBackoff;

#[derive(Clone, Debug)]
pub struct SubscriptionConfig {
    pub fetch_size: u64,
    pub poll_interval_ms: u64,
    pub max_poll_interval_ms: u64,
    pub queue_size: usize,
}

type JitterBackoff = Map<ExponentialBackoff, fn(Duration) -> Duration>;

/// Jitter up to 80% of the actual value
pub fn jitter(duration: Duration) -> Duration {
    // Generate a float from 0.8<->1.0
    let jitter = 0.8 + rand::random::<f64>() / 5.0;
    duration.mul_f64(jitter)
}

pub fn create_backoff(poll_interval_ms: u64, max_poll_interval_ms: u64) -> JitterBackoff {
    ExponentialBackoff::from_millis(poll_interval_ms)
        .max_delay(tokio::time::Duration::from_millis(max_poll_interval_ms))
        .map(jitter)
}

#[derive(Clone)]
pub struct SubscriptionHelper {
    pub db: Arc<dyn DbReader>,
    pub client: ClientConnection,
    pub jsonrpc_id: Id,
    pub method: StreamMethod,
    pub backoff: JitterBackoff,
}

impl SubscriptionHelper {
    pub fn new(
        db: Arc<dyn DbReader>,
        client: ClientConnection,
        jsonrpc_id: Id,
        method: StreamMethod,
    ) -> Self {
        let poll_interval_ms = client.config.poll_interval_ms;
        let max_poll_interval_ms = client.config.max_poll_interval_ms;
        Self {
            db,
            client,
            jsonrpc_id,
            method,
            backoff: create_backoff(poll_interval_ms, max_poll_interval_ms),
        }
    }

    /// This is to be one of the first things that a new subscription task must do, to let the client
    /// know that the subscription has been created (some streams may be very sparse, or start with 0 items)
    pub async fn send_ok(&self) {
        counters::SUBSCRIPTION_OKS
            .with_label_values(&[
                self.client.connection_context.transport.as_str(),
                &self.method.as_str(),
                counters::RpcResult::Success.as_str(),
                self.client.connection_context.sdk_info.language.as_str(),
                &self.client.connection_context.sdk_info.version.to_string(),
            ])
            .inc();
        self.client
            .send_success(
                self.jsonrpc_id.clone(),
                &SubscribeResult::ok(self.db.get_latest_version().unwrap_or(0)),
            )
            .await
            .ok();
    }

    pub fn reset_backoff(&mut self) {
        let config = &self.client.config;
        self.backoff = create_backoff(config.poll_interval_ms, config.max_poll_interval_ms);
    }

    pub async fn sleep_wiggled(&mut self) {
        let sleepy_time = self.backoff.next().unwrap();
        debug!(
            "Client#{} Sleeping for {:?}ms as no results for {}",
            self.client.id,
            sleepy_time,
            self.method.as_str()
        );
        tokio::time::sleep(sleepy_time).await;
    }
}

pub trait Subscription<ParamType, ReturnType>: Send + Sync + Clone + Default + 'static
where
    ParamType: Send + Sync + Clone + 'static,
    ReturnType: Send + Sync + Serialize + Clone,
{
    fn init(&mut self, helper: &SubscriptionHelper, params: &ParamType)
        -> Result<(), JsonRpcError>;
    fn next(&self, helper: &SubscriptionHelper, params: &ParamType) -> Vec<ReturnType>;
    fn on_send(&mut self, item: Option<&ReturnType>);

    fn run(
        mut self,
        mut helper: SubscriptionHelper,
        params: ParamType,
    ) -> Result<JoinHandle<()>, JsonRpcError> {
        self.init(&helper, &params)?;

        Ok(tokio::spawn(async move {
            helper.send_ok().await;

            loop {
                let items = self.next(&helper, &params);

                debug!(
                    "Client#{}: fetched {} items for {}",
                    helper.client.id,
                    items.len(),
                    helper.method.as_str()
                );

                if items.is_empty() {
                    self.on_send(None);
                    helper.sleep_wiggled().await;
                    continue;
                }

                helper.reset_backoff();

                counters::SUBSCRIPTION_RPC_SENT
                    .with_label_values(&[
                        helper.client.connection_context.transport.as_str(),
                        helper.method.as_str(),
                        counters::RpcResult::Success.as_str(),
                        helper.client.connection_context.sdk_info.language.as_str(),
                        &helper
                            .client
                            .connection_context
                            .sdk_info
                            .version
                            .to_string(),
                    ])
                    .inc_by(items.len() as u64);

                for item in items {
                    match helper
                        .client
                        .send_success(helper.jsonrpc_id.clone(), &item)
                        .await
                    {
                        Err(e) => {
                            // client has disconnected
                            debug!("Client#{}: Send error: {:?}", &helper.client.id, e);
                            return;
                        }
                        Ok(_) => self.on_send(Some(&item)),
                    };
                }
            }
        }))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        stream_rpc::tests::util::{create_client_connection, timeout},
        tests::utils::MockDiemDB,
    };
    use diem_json_rpc_types::stream::errors::StreamError;
    use serde::{Deserialize, Serialize};
    use std::time::Instant;
    use tokio::sync::mpsc::Receiver;

    #[derive(Clone, Debug, Deserialize, Serialize)]
    pub struct SubscribeTestParams {
        pub is_valid: bool,
        pub items_to_send: Vec<Vec<TestView>>,
    }

    #[derive(Clone, Copy, Debug, Default)]
    pub struct TestSubscription {
        pub item_index: usize,
    }

    #[derive(Clone, Copy, Debug, Deserialize, Serialize)]
    pub struct TestView {
        pub value: u64,
    }

    impl Subscription<SubscribeTestParams, TestView> for TestSubscription {
        fn init(
            &mut self,
            _helper: &SubscriptionHelper,
            params: &SubscribeTestParams,
        ) -> Result<(), JsonRpcError> {
            // Pretend there's a problem with one of the params
            if params.is_valid {
                Ok(())
            } else {
                Err(JsonRpcError::invalid_param("not is_valid"))
            }
        }

        fn next(
            &self,
            _helper: &SubscriptionHelper,
            params: &SubscribeTestParams,
        ) -> Vec<TestView> {
            let items: Option<&Vec<TestView>> = params.items_to_send.get(self.item_index);
            match items {
                None => vec![],
                Some(items) => items.clone(),
            }
        }

        fn on_send(&mut self, _tx: Option<&TestView>) {
            self.item_index += 1;
        }
    }

    fn create_subscription_helper() -> (
        MockDiemDB,
        ClientConnection,
        Receiver<Result<String, StreamError>>,
        SubscriptionHelper,
    ) {
        let (mock_db, client_connection, receiver) = create_client_connection();

        // The 'method' does not matter for this test (it's used for logging)
        let subscription_helper = SubscriptionHelper::new(
            Arc::new(mock_db.clone()),
            client_connection.clone(),
            Id::Number(1010101),
            StreamMethod::SubscribeToTransactions,
        );

        (mock_db, client_connection, receiver, subscription_helper)
    }

    #[tokio::test]
    async fn test_subscription() {
        let (mock_db, _, mut receiver, subscription_helper) = create_subscription_helper();

        let test_items = vec![
            // Send two items
            vec![TestView { value: 0 }, TestView { value: 1 }],
            // Then don't send anything, and increase the exponential delay
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            vec![],
            // Send some values: the exponential delay should reset
            vec![TestView { value: 2 }],
            vec![TestView { value: 3 }],
        ];

        let params = SubscribeTestParams {
            is_valid: true,
            items_to_send: test_items,
        };

        let handle = TestSubscription::default()
            .run(subscription_helper, params)
            .unwrap();
        let ok_msg = receiver.recv().await;

        let result = ok_msg.unwrap().unwrap();
        let expected = serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result": {"status": "OK", "transaction_version": mock_db.version}}).to_string();
        assert_eq!(expected, result);

        // These should have no delay
        let expected =
            serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result":{"value": 0}}).to_string();
        let next = timeout(1_000, receiver.recv(), "message 0")
            .await
            .unwrap()
            .unwrap();
        assert_eq!(expected, next);

        let expected =
            serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result":{"value": 1}}).to_string();
        let next = timeout(1_000, receiver.recv(), "message 1")
            .await
            .unwrap()
            .unwrap();
        assert_eq!(expected, next);

        // Here we have many iterations which return nothing, so the exponential delay should kick in
        let start = Instant::now();
        let expected =
            serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result":{"value": 2}}).to_string();
        let next = timeout(3_000, receiver.recv(), "message 2")
            .await
            .unwrap()
            .unwrap();
        let elapsed = start.elapsed().as_millis();
        assert_eq!(expected, next);
        assert!(elapsed > 500);

        // This one should have no delay again, due to being reset by the previous message
        let expected =
            serde_json::json!({"jsonrpc": "2.0", "id": 1010101, "result":{"value": 3}}).to_string();
        let next = timeout(1_000, receiver.recv(), "message 3")
            .await
            .unwrap()
            .unwrap();
        assert_eq!(expected, next);
        handle.abort();
    }

    #[tokio::test]
    async fn test_init_rejects_subscription() {
        let (_, _, mut receiver, subscription_helper) = create_subscription_helper();

        let params = SubscribeTestParams {
            is_valid: false,
            items_to_send: vec![],
        };

        let handle = TestSubscription::default().run(subscription_helper, params);

        assert!(handle.is_err());
        let expected = serde_json::json!({"code":-32602, "message": "Invalid param not is_valid", "data": null}).to_string();
        assert_eq!(
            expected,
            serde_json::to_string(&handle.err().unwrap()).unwrap()
        );

        // This is expected to be `None` as the client_connection is dropped
        let ok_msg = receiver.recv().await;
        assert!(ok_msg.is_none());
    }

    #[tokio::test]
    async fn test_sleep_jitter_await() {
        let (_, _, _, mut subscription_helper) = create_subscription_helper();

        let mut results = vec![];

        let start = Instant::now();
        let mut last: u64 = 0;

        for _ in 0..10 {
            subscription_helper.sleep_wiggled().await;
            let elapsed = start.elapsed().as_millis() as u64;
            results.push(elapsed - last);
            last = elapsed;
        }

        // In the event the test fails, this println makes it much easier to debug
        println!("jittered sleeps: {:?}", results);

        // 80 Jitter makes exact comparison hard, but exponentially increasing values here should be > 1.8x the previous one
        for i in 5..9 {
            let prev = *results.get(i).unwrap() as f64;
            let curr = *results.get(i + 1).unwrap() as f64 * 1.8;
            assert!(prev < curr);
        }

        subscription_helper.reset_backoff();
        timeout(
            50,
            subscription_helper.sleep_wiggled(),
            "sleep_wiggled after reset_backoff",
        )
        .await;
    }
}
<|endoftext|>


<commit_before>//! `crypto_scalarmult_curve25519` specified in
//! [Cryptography in NaCl](http://nacl.cr.yp.to/valid.html), Sections 2, 3, and 4.
//! This function is conjectured to be strong. For background see Bernstein,
//! "Curve25519: new Diffie-Hellman speed records," Lecture Notes in Computer
//! Science 3958 (2006), 207–228, http://cr.yp.to/papers.html#curve25519.
use ffi;

pub const BYTES: usize = ffi::crypto_scalarmult_curve25519_BYTES;
pub const SCALARBYTES: usize = ffi::crypto_scalarmult_curve25519_SCALARBYTES;

/// `Scalar` value (integer in byte representation)
#[derive(Copy)]
pub struct Scalar(pub [u8; SCALARBYTES]);

newtype_drop!(Scalar);
newtype_clone!(Scalar);
newtype_impl!(Scalar, SCALARBYTES);

/// `GroupElement`
#[derive(Copy)]
pub struct GroupElement(pub [u8; BYTES]);

newtype_clone!(GroupElement);
newtype_impl!(GroupElement, BYTES);

/// `scalarmult()` multiplies a group element `p`
/// by an integer `n`. It returns the resulting group element
/// `q`.
pub fn scalarmult(&Scalar(ref n): &Scalar,
                  &GroupElement(ref p): &GroupElement) -> GroupElement {
    let mut q = [0; BYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519(&mut q, n, p);
    }
    GroupElement(q)
}

/// `scalarmult_base()` computes the scalar product of a standard
/// group element and an integer `n`. It returns the resulting
/// group element `q`/
pub fn scalarmult_base(&Scalar(ref n): &Scalar) -> GroupElement {
    let mut q = [0; BYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519_base(&mut q, n);
    }
    GroupElement(q)
}

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

    #[test]
    fn test_vector_1() {
        // corresponding to tests/scalarmult.c and tests/scalarmult3.cpp from NaCl
        let alicesk = Scalar([0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
                             ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
                             ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
                             ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a]);
        let alicepk_expected = [0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
                               ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
                               ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
                               ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a];
        let GroupElement(alicepk) = scalarmult_base(&alicesk);
        assert!(alicepk == alicepk_expected);
    }

    #[test]
    fn test_vector_2() {
        // corresponding to tests/scalarmult2.c and tests/scalarmult4.cpp from NaCl
        let bobsk = Scalar([0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
                           ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
                           ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
                           ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb]);
        let bobpk_expected = [0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
                             ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
                             ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
                             ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f];
        let GroupElement(bobpk) = scalarmult_base(&bobsk);
        assert!(bobpk == bobpk_expected);
    }

    #[test]
    fn test_vector_3() {
        // corresponding to tests/scalarmult5.c and tests/scalarmult7.cpp from NaCl
        let alicesk = Scalar([0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
                             ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
                             ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
                             ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a]);
        let bobpk = GroupElement([0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
                                 ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
                                 ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
                                 ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f]);
        let k_expected = [0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
                         ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
                         ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
                         ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42];
        let GroupElement(k) = scalarmult(&alicesk, &bobpk);
        assert!(k == k_expected);
    }

    #[test]
    fn test_vector_4() {
        // corresponding to tests/scalarmult6.c from NaCl
        let bobsk = Scalar([0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
                           ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
                           ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
                           ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb]);
        let alicepk = GroupElement([0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
                                   ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
                                   ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
                                   ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a]);
        let k_expected = [0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
                         ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
                         ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
                         ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42];
        let GroupElement(k) = scalarmult(&bobsk, &alicepk);
        assert!(k == k_expected);
    }
}

#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod bench {
    extern crate test;
    use randombytes::randombytes_into;
    use super::*;

    #[bench]
    fn bench_scalarmult(b: &mut test::Bencher) {
        let mut gbs = [0u8; BYTES];
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut gbs);
        randombytes_into(&mut sbs);
        let g = GroupElement(gbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult(&s, &g);
        });
    }

    #[bench]
    fn bench_scalarmult_base(b: &mut test::Bencher) {
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut sbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult_base(&s);
        });
    }
}
<commit_msg>Remove derived Copy for private key<commit_after>//! `crypto_scalarmult_curve25519` specified in
//! [Cryptography in NaCl](http://nacl.cr.yp.to/valid.html), Sections 2, 3, and 4.
//! This function is conjectured to be strong. For background see Bernstein,
//! "Curve25519: new Diffie-Hellman speed records," Lecture Notes in Computer
//! Science 3958 (2006), 207–228, http://cr.yp.to/papers.html#curve25519.
use ffi;

pub const BYTES: usize = ffi::crypto_scalarmult_curve25519_BYTES;
pub const SCALARBYTES: usize = ffi::crypto_scalarmult_curve25519_SCALARBYTES;

/// `Scalar` value (integer in byte representation)
pub struct Scalar(pub [u8; SCALARBYTES]);

newtype_drop!(Scalar);
newtype_clone!(Scalar);
newtype_impl!(Scalar, SCALARBYTES);

/// `GroupElement`
#[derive(Copy)]
pub struct GroupElement(pub [u8; BYTES]);

newtype_clone!(GroupElement);
newtype_impl!(GroupElement, BYTES);

/// `scalarmult()` multiplies a group element `p`
/// by an integer `n`. It returns the resulting group element
/// `q`.
pub fn scalarmult(&Scalar(ref n): &Scalar,
                  &GroupElement(ref p): &GroupElement) -> GroupElement {
    let mut q = [0; BYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519(&mut q, n, p);
    }
    GroupElement(q)
}

/// `scalarmult_base()` computes the scalar product of a standard
/// group element and an integer `n`. It returns the resulting
/// group element `q`/
pub fn scalarmult_base(&Scalar(ref n): &Scalar) -> GroupElement {
    let mut q = [0; BYTES];
    unsafe {
        ffi::crypto_scalarmult_curve25519_base(&mut q, n);
    }
    GroupElement(q)
}

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

    #[test]
    fn test_vector_1() {
        // corresponding to tests/scalarmult.c and tests/scalarmult3.cpp from NaCl
        let alicesk = Scalar([0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
                             ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
                             ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
                             ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a]);
        let alicepk_expected = [0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
                               ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
                               ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
                               ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a];
        let GroupElement(alicepk) = scalarmult_base(&alicesk);
        assert!(alicepk == alicepk_expected);
    }

    #[test]
    fn test_vector_2() {
        // corresponding to tests/scalarmult2.c and tests/scalarmult4.cpp from NaCl
        let bobsk = Scalar([0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
                           ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
                           ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
                           ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb]);
        let bobpk_expected = [0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
                             ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
                             ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
                             ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f];
        let GroupElement(bobpk) = scalarmult_base(&bobsk);
        assert!(bobpk == bobpk_expected);
    }

    #[test]
    fn test_vector_3() {
        // corresponding to tests/scalarmult5.c and tests/scalarmult7.cpp from NaCl
        let alicesk = Scalar([0x77,0x07,0x6d,0x0a,0x73,0x18,0xa5,0x7d
                             ,0x3c,0x16,0xc1,0x72,0x51,0xb2,0x66,0x45
                             ,0xdf,0x4c,0x2f,0x87,0xeb,0xc0,0x99,0x2a
                             ,0xb1,0x77,0xfb,0xa5,0x1d,0xb9,0x2c,0x2a]);
        let bobpk = GroupElement([0xde,0x9e,0xdb,0x7d,0x7b,0x7d,0xc1,0xb4
                                 ,0xd3,0x5b,0x61,0xc2,0xec,0xe4,0x35,0x37
                                 ,0x3f,0x83,0x43,0xc8,0x5b,0x78,0x67,0x4d
                                 ,0xad,0xfc,0x7e,0x14,0x6f,0x88,0x2b,0x4f]);
        let k_expected = [0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
                         ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
                         ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
                         ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42];
        let GroupElement(k) = scalarmult(&alicesk, &bobpk);
        assert!(k == k_expected);
    }

    #[test]
    fn test_vector_4() {
        // corresponding to tests/scalarmult6.c from NaCl
        let bobsk = Scalar([0x5d,0xab,0x08,0x7e,0x62,0x4a,0x8a,0x4b
                           ,0x79,0xe1,0x7f,0x8b,0x83,0x80,0x0e,0xe6
                           ,0x6f,0x3b,0xb1,0x29,0x26,0x18,0xb6,0xfd
                           ,0x1c,0x2f,0x8b,0x27,0xff,0x88,0xe0,0xeb]);
        let alicepk = GroupElement([0x85,0x20,0xf0,0x09,0x89,0x30,0xa7,0x54
                                   ,0x74,0x8b,0x7d,0xdc,0xb4,0x3e,0xf7,0x5a
                                   ,0x0d,0xbf,0x3a,0x0d,0x26,0x38,0x1a,0xf4
                                   ,0xeb,0xa4,0xa9,0x8e,0xaa,0x9b,0x4e,0x6a]);
        let k_expected = [0x4a,0x5d,0x9d,0x5b,0xa4,0xce,0x2d,0xe1
                         ,0x72,0x8e,0x3b,0xf4,0x80,0x35,0x0f,0x25
                         ,0xe0,0x7e,0x21,0xc9,0x47,0xd1,0x9e,0x33
                         ,0x76,0xf0,0x9b,0x3c,0x1e,0x16,0x17,0x42];
        let GroupElement(k) = scalarmult(&bobsk, &alicepk);
        assert!(k == k_expected);
    }
}

#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod bench {
    extern crate test;
    use randombytes::randombytes_into;
    use super::*;

    #[bench]
    fn bench_scalarmult(b: &mut test::Bencher) {
        let mut gbs = [0u8; BYTES];
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut gbs);
        randombytes_into(&mut sbs);
        let g = GroupElement(gbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult(&s, &g);
        });
    }

    #[bench]
    fn bench_scalarmult_base(b: &mut test::Bencher) {
        let mut sbs = [0u8; SCALARBYTES];
        randombytes_into(&mut sbs);
        let s = Scalar(sbs);
        b.iter(|| {
            scalarmult_base(&s);
        });
    }
}
<|endoftext|>


<commit_before>use std::net::url::Url;
use url_from_str = std::net::url::from_str;
use std::cell::Cell;
use util::DataStream;
use values::Specified;
use color::{Color, rgb};

fn test_url() -> Url {
    result::unwrap(url_from_str("http://foo.com"))
}

fn style_stream(style: &str) -> DataStream {
    let style = Cell(style.to_str());
    |move style| if !style.is_empty() {
        Some(str::to_bytes(style.take()))
    } else {
        None
    }
}

struct TestHandler {
    bogus: int
}

impl TestHandler {
    static fn new() -> TestHandler {
        TestHandler {
            bogus: 0
        }
    }
}

impl TestHandler: SelectHandler<int> {
    fn node_name(_node: &int) -> ~str { ~"div" }
}

fn single_div_test(style: &str, f: &fn(&ComputedStyle)) {
    let sheet = Stylesheet::new(test_url(), style_stream(style));
    let mut select_ctx = SelectCtx::new();
    let handler = &TestHandler::new();
    select_ctx.append_sheet(move sheet);
    let dom = &0;
    let style = select_ctx.select_style(dom, handler);
    let computed = style.computed_style();
    f(&computed);
}

#[test]
fn test_background_color_simple() {
    let style = "div { background-color: #123456; }";
    do single_div_test(style) |computed| {
        let color = computed.background_color();
        assert color == Specified(rgb(0x12, 0x34, 0x56));
    }
}
<commit_msg>Add border width tests<commit_after>use std::net::url::Url;
use url_from_str = std::net::url::from_str;
use std::cell::Cell;
use util::DataStream;
use values::Specified;
use color::{Color, rgb};

fn test_url() -> Url {
    result::unwrap(url_from_str("http://foo.com"))
}

fn style_stream(style: &str) -> DataStream {
    let style = Cell(style.to_str());
    |move style| if !style.is_empty() {
        Some(str::to_bytes(style.take()))
    } else {
        None
    }
}

struct TestHandler {
    bogus: int
}

impl TestHandler {
    static fn new() -> TestHandler {
        TestHandler {
            bogus: 0
        }
    }
}

impl TestHandler: SelectHandler<int> {
    fn node_name(_node: &int) -> ~str { ~"div" }
}

fn single_div_test(style: &str, f: &fn(&ComputedStyle)) {
    let sheet = Stylesheet::new(test_url(), style_stream(style));
    let mut select_ctx = SelectCtx::new();
    let handler = &TestHandler::new();
    select_ctx.append_sheet(move sheet);
    let dom = &0;
    let style = select_ctx.select_style(dom, handler);
    let computed = style.computed_style();
    f(&computed);
}

#[test]
fn test_background_color_simple() {
    let style = "div { background-color: #123456; }";
    do single_div_test(style) |computed| {
        let color = computed.background_color();
        assert color == Specified(rgb(0x12, 0x34, 0x56));
    }
}

#[test]
fn test_border_top_width_px() {
    let style = "div { border-top-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_top_width();
        assert width == Specified(Px(10.0));
    }
}

#[test]
fn test_border_right_width_px() {
    let style = "div { border-right-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_right_width();
        assert width == Specified(Px(10.0));
    }
}

#[test]
fn test_border_bottom_width_px() {
    let style = "div { border-bottom-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_bottom_width();
        assert width == Specified(Px(10.0));
    }
}

#[test]
fn test_border_left_width_px() {
    let style = "div { border-left-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_left_width();
        assert width == Specified(Px(10.0));
    }
}

#[test]
fn test_border_width_px() {
    let style = "div { border-width: 10px; }";
    do single_div_test(style) |computed| {
        let width = computed.border_top_width();
        assert width == Specified(Px(10.0));
        let width = computed.border_right_width();
        assert width == Specified(Px(10.0));
        let width = computed.border_bottom_width();
        assert width == Specified(Px(10.0));
        let width = computed.border_left_width();
        assert width == Specified(Px(10.0));
    }
}<|endoftext|>