1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

pub mod error;
pub mod fd;
pub mod net;
pub mod time;

use nss_sys::nspr as ffi;

use std::marker::PhantomData;
use std::sync::{Once, ONCE_INIT};

use GenStatus;
pub use self::fd::File;

pub fn init() {
    // NSPR initialization is done implicitly on the first call to any
    // API, but this "run once" check is thread-unsafe -- NSPR's
    // equivalent of `Once` can't be used because its threading layer
    // isn't initialized yet, and its atomics are polyfilled with
    // thread mutexes on some platforms so they're also off-limits.
    static PR_INIT_ONCE: Once = ONCE_INIT;
    PR_INIT_ONCE.call_once(|| {
        // These argument values haven't been used since before NSPR
        // was released as open source, but fill in something reasonable.
        unsafe {
            ffi::PR_Init(ffi::PR_SYSTEM_THREAD, ffi::PR_PRIORITY_NORMAL, 0);
        }
    });
}

impl From<ffi::PRStatus> for GenStatus<()> {
    fn from(status: ffi::PRStatus) -> Self {
        match status {
            ffi::PR_SUCCESS => GenStatus::Success(()),
            ffi::PR_FAILURE => GenStatus::ErrorFromC,
        }
    }
}

impl From<i32> for GenStatus<usize> {
    fn from(rv: i32) -> Self {
        if rv >= 0 {
            GenStatus::Success(rv as usize)
        } else {
            GenStatus::ErrorFromC
        }
    }
}

pub fn bool_from_nspr(b: ffi::PRBool) -> bool {
    match b {
        ffi::PR_FALSE => false,
        ffi::PR_TRUE => true,
        _ => unreachable!(),
    }
}

pub fn bool_to_nspr(b: bool) -> ffi::PRBool {
    if b {
        ffi::PR_TRUE
    } else {
        ffi::PR_FALSE
    }
}


pub type ListNode = *mut ffi::PRCList;

pub trait Listable {
    unsafe fn from_list_node(node: ListNode) -> Self;
}

#[derive(Clone, Debug)]
pub struct ListIterator<'l, L: Listable + 'l> {
    next: ListNode,
    end: ListNode,
    phantom: PhantomData<&'l [L]>,
}

impl<'l, L: Listable + 'l> ListIterator<'l, L> {
    pub unsafe fn new(list: ListNode) -> Self {
        ListIterator {
            next: (*list).next,
            end: list,
            phantom: PhantomData,
        }
    }
}

impl<'l, L: Listable + 'l> Iterator for ListIterator<'l, L> {
    type Item = L;
    fn next(&mut self) -> Option<L> {
        if self.next == self.end {
            None
        } else {
            unsafe {
                let next = self.next;
                self.next = (*next).next;
                Some(Listable::from_list_node(next))
            }
        }
    }
}

impl<'l, L: Listable + 'l> DoubleEndedIterator for ListIterator<'l, L> {
    fn next_back(&mut self) -> Option<L> {
        if self.next == self.end {
            None
        } else {
            unsafe {
                let prev = (*self.end).prev;
                self.end = prev;
                Some(Listable::from_list_node(prev))
            }
        }
    }
}