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

use chrono::Utc;
use once_cell::sync::Lazy;
use serde::Serialize;
use serde_json::Value;
use std::{
    collections::HashMap,
    env,
    fmt::Display,
    fs::{File, OpenOptions},
    io,
    io::Write as IoWrite,
    marker::PhantomData,
    net::UdpSocket,
    str::FromStr,
    sync::{
        atomic::{AtomicUsize, Ordering},
        mpsc::{self, Receiver, SyncSender},
    },
    thread,
};

pub trait StructLogSink: Sync {
    fn send(&self, entry: StructuredLogEntry);
}

// This is poor's man AtomicReference from crossbeam
// It have few unsafe lines, but does not require extra dependency
static NOP: NopStructLog = NopStructLog {};
static mut STRUCT_LOGGER: &'static dyn StructLogSink = &NOP;
static STRUCT_LOGGER_STATE: AtomicUsize = AtomicUsize::new(UNINITIALIZED);
const UNINITIALIZED: usize = 0;

const INITIALIZING: usize = 1;
const INITIALIZED: usize = 2;

// severity level - lower is worse
const SEVERITY_CRITICAL: usize = 1;
const SEVERITY_WARNING: usize = 2;

#[derive(Default, Serialize)]
pub struct StructuredLogEntry {
    /// log message set by macros like info!
    #[serde(skip_serializing_if = "Option::is_none")]
    log: Option<String>,
    /// description of the log
    #[serde(skip_serializing_if = "Option::is_none")]
    pattern: Option<&'static str>,
    /// category of the event
    #[serde(skip_serializing_if = "Option::is_none")]
    category: Option<&'static str>,
    /// name of the event
    #[serde(skip_serializing_if = "Option::is_none")]
    name: Option<&'static str>,
    /// rust module (e.g. consensus::round_manager)
    #[serde(skip_serializing_if = "Option::is_none")]
    module: Option<&'static str>,
    /// filename + line (e.g. consensus/src/round_manager.rs:678)
    #[serde(skip_serializing_if = "Option::is_none")]
    location: Option<&'static str>,
    /// git revision
    #[serde(skip_serializing_if = "Option::is_none")]
    git_rev: Option<&'static str>,
    /// time of the log
    #[serde(skip_serializing_if = "Option::is_none")]
    timestamp: Option<String>,
    /// warning or critical
    #[serde(skip_serializing_if = "Option::is_none")]
    severity: Option<usize>,
    /// arbitrary data that can be logged
    #[serde(skip_serializing_if = "HashMap::is_empty")]
    data: HashMap<&'static str, Value>,
}

#[must_use = "use send_struct_log! macro to send structured log"]
impl StructuredLogEntry {
    pub fn new_unnamed() -> Self {
        let mut ret = Self::default();
        ret.timestamp = Some(Utc::now().format("%F %T").to_string());
        ret
    }

    pub fn new_named(category: &'static str, name: &'static str) -> Self {
        let mut ret = Self::default();
        ret.category = Some(category);
        ret.name = Some(name);
        ret.timestamp = Some(Utc::now().format("%F %T").to_string());
        ret
    }

    pub fn critical(mut self) -> Self {
        self.severity = Some(SEVERITY_CRITICAL);
        self
    }

    pub fn warning(mut self) -> Self {
        self.severity = Some(SEVERITY_WARNING);
        self
    }

    pub fn json_data(mut self, key: &'static str, value: Value) -> Self {
        self.data.insert(key, value);
        self
    }

    pub fn data<D: Serialize>(mut self, key: &'static str, value: D) -> Self {
        self.data.insert(
            key,
            serde_json::to_value(value).expect("Failed to serialize StructuredLogEntry key"),
        );
        self
    }

    /// Used for errors and other types that don't serialize well
    pub fn data_display<D: Display>(self, key: &'static str, value: D) -> Self {
        self.data(key, value.to_string())
    }

    pub fn field<D: Serialize>(self, field: &LoggingField<D>, value: D) -> Self {
        self.data(field.0, value)
    }

    #[doc(hidden)] // set from macro
    pub fn log(&mut self, log: String) -> &mut Self {
        self.log = Some(log);
        self
    }

    #[doc(hidden)] // set from macro
    pub fn pattern(&mut self, pattern: &'static str) -> &mut Self {
        self.pattern = Some(pattern);
        self
    }

    #[doc(hidden)] // set from macro
    pub fn module(&mut self, module: &'static str) -> &mut Self {
        self.module = Some(module);
        self
    }

    #[doc(hidden)] // set from macro
    pub fn location(&mut self, location: &'static str) -> &mut Self {
        self.location = Some(location);
        self
    }

    #[doc(hidden)] // set from macro
    pub fn git_rev(&mut self, git_rev: Option<&'static str>) -> &mut Self {
        self.git_rev = git_rev;
        self
    }

    #[doc(hidden)] // set from macro
    pub fn data_mutref<D: Serialize>(&mut self, key: &'static str, value: D) -> &mut Self {
        self.data.insert(
            key,
            serde_json::to_value(value).expect("Failed to serialize StructuredLogEntry key"),
        );
        self
    }

    // Use send_struct_log! macro instead of this method to populate extra meta information such as git rev and module name
    #[doc(hidden)]
    pub fn send(self) {
        struct_logger().send(self);
    }
}

/// Field is similar to .data but restricts type of the value to a specific type.
///
/// Example:
///
/// mod logging {
///    pub const MY_FIELD:LoggingField<u64> = LoggingField::new("my_field");
/// }
///
/// mod my_code {
///    fn my_fn() {
///        send_struct_log!(StructuredLogEntry::new(...).field(&logging::MY_FIELD, 0))
///    }
/// }
pub struct LoggingField<D>(&'static str, PhantomData<D>);

impl<D> LoggingField<D> {
    pub const fn new(name: &'static str) -> Self {
        Self(name, PhantomData)
    }
}

// This is exact copy of similar function in log crate
/// Sets structured logger
pub fn set_struct_logger(logger: &'static dyn StructLogSink) -> Result<(), ()> {
    unsafe {
        match STRUCT_LOGGER_STATE.compare_and_swap(UNINITIALIZED, INITIALIZING, Ordering::SeqCst) {
            UNINITIALIZED => {
                STRUCT_LOGGER = logger;
                STRUCT_LOGGER_STATE.store(INITIALIZED, Ordering::SeqCst);
                Ok(())
            }
            INITIALIZING => {
                while STRUCT_LOGGER_STATE.load(Ordering::SeqCst) == INITIALIZING {}
                Err(())
            }
            _ => Err(()),
        }
    }
}

static STRUCT_LOG_LEVEL: Lazy<log::Level> = Lazy::new(|| {
    let level = env::var("STRUCT_LOG_LEVEL").unwrap_or_else(|_| "debug".to_string());
    log::Level::from_str(&level).expect("Failed to parse log level")
});

/// Checks if structured logging is enabled for level
pub fn struct_logger_enabled(level: log::Level) -> bool {
    struct_logger_set() && level <= *STRUCT_LOG_LEVEL
}

/// Checks if structured logging is enabled
pub fn struct_logger_set() -> bool {
    STRUCT_LOGGER_STATE.load(Ordering::SeqCst) == INITIALIZED
}

/// Initializes struct logger from STRUCT_LOG_FILE env var.
/// If STRUCT_LOG_FILE is set, STRUCT_LOG_UDP_ADDR will be ignored.
/// Can only be called once
pub fn init_struct_log_from_env() -> Result<(), InitLoggerError> {
    if let Ok(file) = env::var("STRUCT_LOG_FILE") {
        init_file_struct_log(file)
    } else if let Ok(udp_address) = env::var("STRUCT_LOG_UDP_ADDR") {
        init_udp_struct_log(udp_address)
    } else {
        Ok(())
    }
}

/// Initializes struct logger sink that writes to specified file.
/// Can only be called once
pub fn init_file_struct_log(file_path: String) -> Result<(), InitLoggerError> {
    let logger = FileStructLog::start_new(file_path).map_err(InitLoggerError::IoError)?;
    let logger = Box::leak(Box::new(logger));
    set_struct_logger(logger).map_err(|_| InitLoggerError::StructLoggerAlreadySet)
}

/// Initializes struct logger sink that stream logs through UDP protocol.
/// Can only be called once
pub fn init_udp_struct_log(udp_address: String) -> Result<(), InitLoggerError> {
    let logger = UDPStructLog::start_new(udp_address).map_err(InitLoggerError::IoError)?;
    let logger = Box::leak(Box::new(logger));
    set_struct_logger(logger).map_err(|_| InitLoggerError::StructLoggerAlreadySet)
}

/// Initialize struct logger sink that prints all structured logs to stdout
/// Can only be called once
pub fn init_println_struct_log() -> Result<(), ()> {
    let logger = PrintStructLog {};
    let logger = Box::leak(Box::new(logger));
    set_struct_logger(logger)
}

#[derive(Debug)]
pub enum InitLoggerError {
    IoError(io::Error),
    StructLoggerAlreadySet,
}

// This is exact copy of similar function in log crate
fn struct_logger() -> &'static dyn StructLogSink {
    unsafe {
        if STRUCT_LOGGER_STATE.load(Ordering::SeqCst) != INITIALIZED {
            &NOP
        } else {
            STRUCT_LOGGER
        }
    }
}

struct NopStructLog {}

impl StructLogSink for NopStructLog {
    fn send(&self, _entry: StructuredLogEntry) {}
}

struct PrintStructLog {}

impl StructLogSink for PrintStructLog {
    fn send(&self, entry: StructuredLogEntry) {
        println!("{}", serde_json::to_string(&entry).unwrap());
    }
}

/// Sink that prints all structured logs to specified file
struct FileStructLog {
    sender: SyncSender<StructuredLogEntry>,
}

impl FileStructLog {
    /// Creates new FileStructLog and starts async thread to write results
    pub fn start_new(file_path: String) -> io::Result<Self> {
        let (sender, receiver) = mpsc::sync_channel(1_024);
        let file = OpenOptions::new()
            .append(true)
            .create(true)
            .open(file_path)?;
        let sink_thread = FileStructLogThread { receiver, file };
        thread::spawn(move || sink_thread.run());
        Ok(Self { sender })
    }
}

impl StructLogSink for FileStructLog {
    fn send(&self, entry: StructuredLogEntry) {
        if let Err(e) = self.sender.try_send(entry) {
            // Use log crate macro to avoid generation of structured log in this case
            // Otherwise we will have infinite loop
            log::error!("Failed to send structured log: {}", e);
        }
    }
}

struct FileStructLogThread {
    receiver: Receiver<StructuredLogEntry>,
    file: File,
}

impl FileStructLogThread {
    pub fn run(mut self) {
        for entry in self.receiver {
            let json = match serde_json::to_value(entry) {
                Err(e) => {
                    log::error!("Failed to serialize struct log entry: {}", e);
                    continue;
                }
                Ok(json) => json,
            };
            if let Err(e) = writeln!(&mut self.file, "{}", json) {
                log::error!("Failed to write struct log entry: {}", e);
            }
        }
    }
}

/// Sink that streams all structured logs to an address through UDP protocol
struct UDPStructLog {
    sender: SyncSender<StructuredLogEntry>,
}

impl UDPStructLog {
    /// Creates new UDPStructLog and starts async thread to send results
    pub fn start_new(udp_address: String) -> io::Result<Self> {
        let (sender, receiver) = mpsc::sync_channel(1_024);
        let socket = UdpSocket::bind("0.0.0.0:0").expect("couldn't bind to address");
        let sink_thread = UDPStructLogThread {
            receiver,
            socket,
            udp_address,
        };
        thread::spawn(move || sink_thread.run());
        Ok(Self { sender })
    }
}

impl StructLogSink for UDPStructLog {
    fn send(&self, entry: StructuredLogEntry) {
        if let Err(e) = self.sender.try_send(entry) {
            // Use log crate macro to avoid generation of structured log in this case
            // Otherwise we will have infinite loop
            log::error!("[Logging] Failed to send structured log: {}", e);
        }
    }
}

struct UDPStructLogThread {
    receiver: Receiver<StructuredLogEntry>,
    socket: UdpSocket,
    udp_address: String,
}

impl UDPStructLogThread {
    pub fn run(self) {
        for entry in self.receiver {
            let json = match serde_json::to_value(entry) {
                Err(e) => {
                    log::error!("[Logging] Failed to serialize struct log entry: {}", e);
                    continue;
                }
                Ok(json) => json,
            };
            match self
                .socket
                .send_to(json.to_string().as_bytes(), self.udp_address.clone())
            {
                Ok(_) => {
                    continue;
                }
                Err(e) => {
                    // do not break on error, move on to the next log message
                    println!("[Logging] Error while sending data to socket: {}", e);
                }
            }
        }
    }
}
<commit_msg>[logging] add a maximum size to structured logging<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use chrono::Utc;
use once_cell::sync::Lazy;
use serde::Serialize;
use serde_json::Value;
use std::{
    collections::HashMap,
    env,
    fmt::Display,
    fs::{File, OpenOptions},
    io,
    io::Write as IoWrite,
    marker::PhantomData,
    net::UdpSocket,
    str::FromStr,
    sync::{
        atomic::{AtomicUsize, Ordering},
        mpsc::{self, Receiver, SyncSender},
    },
    thread,
};

pub trait StructLogSink: Sync {
    fn send(&self, entry: StructuredLogEntry);
}

// This is poor's man AtomicReference from crossbeam
// It have few unsafe lines, but does not require extra dependency
static NOP: NopStructLog = NopStructLog {};
static mut STRUCT_LOGGER: &'static dyn StructLogSink = &NOP;
static STRUCT_LOGGER_STATE: AtomicUsize = AtomicUsize::new(UNINITIALIZED);
const UNINITIALIZED: usize = 0;

const INITIALIZING: usize = 1;
const INITIALIZED: usize = 2;

// severity level - lower is worse
const SEVERITY_CRITICAL: usize = 1;
const SEVERITY_WARNING: usize = 2;

// Size configurations
const MAX_LOG_LINE_SIZE: usize = 4096; // 4KiB
const LOG_INFO_OFFSET: usize = 256;
const WRITE_CHANNEL_SIZE: usize = 1024;

#[derive(Default, Serialize)]
pub struct StructuredLogEntry {
    /// log message set by macros like info!
    #[serde(skip_serializing_if = "Option::is_none")]
    log: Option<String>,
    /// description of the log
    #[serde(skip_serializing_if = "Option::is_none")]
    pattern: Option<&'static str>,
    /// category of the event
    #[serde(skip_serializing_if = "Option::is_none")]
    category: Option<&'static str>,
    /// name of the event
    #[serde(skip_serializing_if = "Option::is_none")]
    name: Option<&'static str>,
    /// rust module (e.g. consensus::round_manager)
    #[serde(skip_serializing_if = "Option::is_none")]
    module: Option<&'static str>,
    /// filename + line (e.g. consensus/src/round_manager.rs:678)
    #[serde(skip_serializing_if = "Option::is_none")]
    location: Option<&'static str>,
    /// git revision
    #[serde(skip_serializing_if = "Option::is_none")]
    git_rev: Option<&'static str>,
    /// time of the log
    #[serde(skip_serializing_if = "Option::is_none")]
    timestamp: Option<String>,
    /// warning or critical
    #[serde(skip_serializing_if = "Option::is_none")]
    severity: Option<usize>,
    /// arbitrary data that can be logged
    #[serde(skip_serializing_if = "HashMap::is_empty")]
    data: HashMap<&'static str, Value>,
}

#[must_use = "use send_struct_log! macro to send structured log"]
impl StructuredLogEntry {
    pub fn new_unnamed() -> Self {
        let mut ret = Self::default();
        ret.timestamp = Some(Utc::now().format("%F %T").to_string());
        ret
    }

    pub fn new_named(category: &'static str, name: &'static str) -> Self {
        let mut ret = Self::default();
        ret.category = Some(category);
        ret.name = Some(name);
        ret.timestamp = Some(Utc::now().format("%F %T").to_string());
        ret
    }

    fn clone_without_data(&self) -> Self {
        Self {
            log: self.log.clone(),
            pattern: self.pattern,
            category: self.category,
            name: self.name,
            module: self.module,
            location: self.location,
            git_rev: self.git_rev,
            timestamp: self.timestamp.clone(),
            severity: self.severity,
            data: HashMap::new(),
        }
    }

    fn to_json(&self) -> Result<Value, serde_json::Error> {
        let value = serde_json::to_value(self);
        if let Err(e) = &value {
            log::error!("[Logging] Failed to serialize struct log entry: {}", e);
        }
        value
    }

    fn to_json_string(&self) -> Result<String, serde_json::Error> {
        let json = self.to_json()?;

        // If the message is too long, let's truncate the message and leave helpful info
        let mut json_string = json.to_string();
        if json_string.len() > MAX_LOG_LINE_SIZE {
            log::error!(
                "[Logging] Structured log is too long, shrinking below : {}",
                MAX_LOG_LINE_SIZE
            );

            let mut entry = self.clone_without_data();
            if let Some(mut log) = entry.log {
                log.truncate(MAX_LOG_LINE_SIZE - LOG_INFO_OFFSET);
                // Leave 128 bytes for all the other info
                entry.log = Some(log);
            }
            entry = entry
                .data(
                    "StructLogError",
                    format!("Message exceeded MAX_LOG_LINE_SIZE {}", MAX_LOG_LINE_SIZE),
                )
                .data("OriginalLength", json_string.len());
            json_string = entry.to_json()?.to_string();
        }

        Ok(json_string)
    }

    pub fn critical(mut self) -> Self {
        self.severity = Some(SEVERITY_CRITICAL);
        self
    }

    pub fn warning(mut self) -> Self {
        self.severity = Some(SEVERITY_WARNING);
        self
    }

    pub fn json_data(mut self, key: &'static str, value: Value) -> Self {
        self.data.insert(key, value);
        self
    }

    pub fn data<D: Serialize>(mut self, key: &'static str, value: D) -> Self {
        self.data.insert(
            key,
            serde_json::to_value(value).expect("Failed to serialize StructuredLogEntry key"),
        );
        self
    }

    /// Used for errors and other types that don't serialize well
    pub fn data_display<D: Display>(self, key: &'static str, value: D) -> Self {
        self.data(key, value.to_string())
    }

    pub fn field<D: Serialize>(self, field: &LoggingField<D>, value: D) -> Self {
        self.data(field.0, value)
    }

    #[doc(hidden)] // set from macro
    pub fn log(&mut self, log: String) -> &mut Self {
        self.log = Some(log);
        self
    }

    #[doc(hidden)] // set from macro
    pub fn pattern(&mut self, pattern: &'static str) -> &mut Self {
        self.pattern = Some(pattern);
        self
    }

    #[doc(hidden)] // set from macro
    pub fn module(&mut self, module: &'static str) -> &mut Self {
        self.module = Some(module);
        self
    }

    #[doc(hidden)] // set from macro
    pub fn location(&mut self, location: &'static str) -> &mut Self {
        self.location = Some(location);
        self
    }

    #[doc(hidden)] // set from macro
    pub fn git_rev(&mut self, git_rev: Option<&'static str>) -> &mut Self {
        self.git_rev = git_rev;
        self
    }

    #[doc(hidden)] // set from macro
    pub fn data_mutref<D: Serialize>(&mut self, key: &'static str, value: D) -> &mut Self {
        self.data.insert(
            key,
            serde_json::to_value(value).expect("Failed to serialize StructuredLogEntry key"),
        );
        self
    }

    // Use send_struct_log! macro instead of this method to populate extra meta information such as git rev and module name
    #[doc(hidden)]
    pub fn send(self) {
        struct_logger().send(self);
    }
}

/// Field is similar to .data but restricts type of the value to a specific type.
///
/// Example:
///
/// mod logging {
///    pub const MY_FIELD:LoggingField<u64> = LoggingField::new("my_field");
/// }
///
/// mod my_code {
///    fn my_fn() {
///        send_struct_log!(StructuredLogEntry::new(...).field(&logging::MY_FIELD, 0))
///    }
/// }
pub struct LoggingField<D>(&'static str, PhantomData<D>);

impl<D> LoggingField<D> {
    pub const fn new(name: &'static str) -> Self {
        Self(name, PhantomData)
    }
}

// This is exact copy of similar function in log crate
/// Sets structured logger
pub fn set_struct_logger(logger: &'static dyn StructLogSink) -> Result<(), ()> {
    unsafe {
        match STRUCT_LOGGER_STATE.compare_and_swap(UNINITIALIZED, INITIALIZING, Ordering::SeqCst) {
            UNINITIALIZED => {
                STRUCT_LOGGER = logger;
                STRUCT_LOGGER_STATE.store(INITIALIZED, Ordering::SeqCst);
                Ok(())
            }
            INITIALIZING => {
                while STRUCT_LOGGER_STATE.load(Ordering::SeqCst) == INITIALIZING {}
                Err(())
            }
            _ => Err(()),
        }
    }
}

static STRUCT_LOG_LEVEL: Lazy<log::Level> = Lazy::new(|| {
    let level = env::var("STRUCT_LOG_LEVEL").unwrap_or_else(|_| "debug".to_string());
    log::Level::from_str(&level).expect("Failed to parse log level")
});

/// Checks if structured logging is enabled for level
pub fn struct_logger_enabled(level: log::Level) -> bool {
    struct_logger_set() && level <= *STRUCT_LOG_LEVEL
}

/// Checks if structured logging is enabled
pub fn struct_logger_set() -> bool {
    STRUCT_LOGGER_STATE.load(Ordering::SeqCst) == INITIALIZED
}

/// Initializes struct logger from STRUCT_LOG_FILE env var.
/// If STRUCT_LOG_FILE is set, STRUCT_LOG_UDP_ADDR will be ignored.
/// Can only be called once
pub fn init_struct_log_from_env() -> Result<(), InitLoggerError> {
    if let Ok(file) = env::var("STRUCT_LOG_FILE") {
        init_file_struct_log(file)
    } else if let Ok(udp_address) = env::var("STRUCT_LOG_UDP_ADDR") {
        init_udp_struct_log(udp_address)
    } else {
        Ok(())
    }
}

/// Initializes struct logger sink that writes to specified file.
/// Can only be called once
pub fn init_file_struct_log(file_path: String) -> Result<(), InitLoggerError> {
    let logger = FileStructLog::start_new(file_path).map_err(InitLoggerError::IoError)?;
    let logger = Box::leak(Box::new(logger));
    set_struct_logger(logger).map_err(|_| InitLoggerError::StructLoggerAlreadySet)
}

/// Initializes struct logger sink that stream logs through UDP protocol.
/// Can only be called once
pub fn init_udp_struct_log(udp_address: String) -> Result<(), InitLoggerError> {
    let logger = UDPStructLog::start_new(udp_address).map_err(InitLoggerError::IoError)?;
    let logger = Box::leak(Box::new(logger));
    set_struct_logger(logger).map_err(|_| InitLoggerError::StructLoggerAlreadySet)
}

/// Initialize struct logger sink that prints all structured logs to stdout
/// Can only be called once
pub fn init_println_struct_log() -> Result<(), ()> {
    let logger = PrintStructLog {};
    let logger = Box::leak(Box::new(logger));
    set_struct_logger(logger)
}

#[derive(Debug)]
pub enum InitLoggerError {
    IoError(io::Error),
    StructLoggerAlreadySet,
}

// This is exact copy of similar function in log crate
fn struct_logger() -> &'static dyn StructLogSink {
    unsafe {
        if STRUCT_LOGGER_STATE.load(Ordering::SeqCst) != INITIALIZED {
            &NOP
        } else {
            STRUCT_LOGGER
        }
    }
}

struct NopStructLog {}

impl StructLogSink for NopStructLog {
    fn send(&self, _entry: StructuredLogEntry) {}
}

struct PrintStructLog {}

impl StructLogSink for PrintStructLog {
    fn send(&self, entry: StructuredLogEntry) {
        println!("{}", serde_json::to_string(&entry).unwrap());
    }
}

/// Sink that prints all structured logs to specified file
struct FileStructLog {
    sender: SyncSender<StructuredLogEntry>,
}

impl FileStructLog {
    /// Creates new FileStructLog and starts async thread to write results
    pub fn start_new(file_path: String) -> io::Result<Self> {
        let (sender, receiver) = mpsc::sync_channel(WRITE_CHANNEL_SIZE);
        let file = OpenOptions::new()
            .append(true)
            .create(true)
            .open(file_path)?;
        let sink_thread = FileStructLogThread { receiver, file };
        thread::spawn(move || sink_thread.run());
        Ok(Self { sender })
    }
}

impl StructLogSink for FileStructLog {
    fn send(&self, entry: StructuredLogEntry) {
        if let Err(e) = self.sender.try_send(entry) {
            // Use log crate macro to avoid generation of structured log in this case
            // Otherwise we will have infinite loop
            log::error!("Failed to send structured log: {}", e);
        }
    }
}

struct FileStructLogThread {
    receiver: Receiver<StructuredLogEntry>,
    file: File,
}

impl FileStructLogThread {
    pub fn run(mut self) {
        for entry in self.receiver {
            let json_string = match entry.to_json_string() {
                Ok(json_string) => json_string,
                Err(_) => continue,
            };
            if let Err(e) = writeln!(&mut self.file, "{}", json_string) {
                log::error!("Failed to write struct log entry: {}", e);
            }
        }
    }
}

/// Sink that streams all structured logs to an address through UDP protocol
struct UDPStructLog {
    sender: SyncSender<StructuredLogEntry>,
}

impl UDPStructLog {
    /// Creates new UDPStructLog and starts async thread to send results
    pub fn start_new(udp_address: String) -> io::Result<Self> {
        let (sender, receiver) = mpsc::sync_channel(WRITE_CHANNEL_SIZE);
        let socket = UdpSocket::bind("0.0.0.0:0").expect("couldn't bind to address");
        let sink_thread = UDPStructLogThread {
            receiver,
            socket,
            udp_address,
        };
        thread::spawn(move || sink_thread.run());
        Ok(Self { sender })
    }
}

impl StructLogSink for UDPStructLog {
    fn send(&self, entry: StructuredLogEntry) {
        if let Err(e) = self.sender.try_send(entry) {
            // Use log crate macro to avoid generation of structured log in this case
            // Otherwise we will have infinite loop
            log::error!("[Logging] Failed to send structured log: {}", e);
        }
    }
}

struct UDPStructLogThread {
    receiver: Receiver<StructuredLogEntry>,
    socket: UdpSocket,
    udp_address: String,
}

impl UDPStructLogThread {
    pub fn run(self) {
        for entry in self.receiver {
            let json_string = match entry.to_json_string() {
                Ok(json_string) => json_string,
                Err(_) => continue,
            };
            if let Err(e) = self
                .socket
                .send_to(json_string.as_bytes(), self.udp_address.clone())
            {
                // do not break on error, move on to the next log message
                println!("[Logging] Error while sending data to socket: {}", e);
            }
        }
    }
}
<|endoftext|>


<commit_before>use rustc_attr as attr;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use rustc_target::spec::abi::Abi;

/// Whether the `def_id` counts as const fn in your current crate, considering all active
/// feature gates
pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    tcx.is_const_fn_raw(def_id)
        && match is_unstable_const_fn(tcx, def_id) {
            Some(feature_name) => {
                // has a `rustc_const_unstable` attribute, check whether the user enabled the
                // corresponding feature gate.
                tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
            }
            // functions without const stability are either stable user written
            // const fn or the user is using feature gates and we thus don't
            // care what they do
            None => true,
        }
}

/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
    if tcx.is_const_fn_raw(def_id) {
        let const_stab = tcx.lookup_const_stability(def_id)?;
        if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
    } else {
        None
    }
}

/// Returns `true` if this function must conform to `min_const_fn`
pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    // Bail out if the signature doesn't contain `const`
    if !tcx.is_const_fn_raw(def_id) {
        return false;
    }

    if tcx.features().staged_api {
        // In order for a libstd function to be considered min_const_fn
        // it needs to be stable and have no `rustc_const_unstable` attribute.
        match tcx.lookup_const_stability(def_id) {
            // `rustc_const_unstable` functions don't need to conform.
            Some(&attr::ConstStability { ref level, .. }) if level.is_unstable() => false,
            None => {
                if let Some(stab) = tcx.lookup_stability(def_id) {
                    if stab.level.is_stable() {
                        tcx.sess.delay_span_bug(
                            tcx.def_span(def_id),
                            "stable const functions must have either `rustc_const_stable` or \
                             `rustc_const_unstable` attribute",
                        );
                        // While we errored above, because we don't know if we need to conform, we
                        // err on the "safe" side and require min_const_fn.
                        true
                    } else {
                        // Unstable functions need not conform to min_const_fn.
                        false
                    }
                } else {
                    // Internal functions are forced to conform to min_const_fn.
                    // Annotate the internal function with a const stability attribute if
                    // you need to use unstable features.
                    // Note: this is an arbitrary choice that does not affect stability or const
                    // safety or anything, it just changes whether we need to annotate some
                    // internal functions with `rustc_const_stable` or with `rustc_const_unstable`
                    true
                }
            }
            // Everything else needs to conform, because it would be callable from
            // other `min_const_fn` functions.
            _ => true,
        }
    } else {
        // users enabling the `const_fn` feature gate can do what they want
        !tcx.features().const_fn
    }
}

pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
    let parent_id = tcx.hir().get_parent_did(hir_id);
    if !parent_id.is_top_level_module() { is_const_impl_raw(tcx, parent_id) } else { false }
}

/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
/// said intrinsic has a `rustc_const_{un,}stable` attribute.
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());

    let node = tcx.hir().get(hir_id);

    if let hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) =
        node
    {
        // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
        // foreign items cannot be evaluated at compile-time.
        if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = tcx.hir().get_foreign_abi(hir_id) {
            tcx.lookup_const_stability(def_id).is_some()
        } else {
            false
        }
    } else if let Some(fn_like) = FnLikeNode::from_node(node) {
        if fn_like.constness() == hir::Constness::Const {
            return true;
        }

        // If the function itself is not annotated with `const`, it may still be a `const fn`
        // if it resides in a const trait impl.
        is_parent_const_impl_raw(tcx, hir_id)
    } else if let hir::Node::Ctor(_) = node {
        true
    } else {
        false
    }
}

/// Checks whether the given item is an `impl` that has a `const` modifier.
fn is_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
    let node = tcx.hir().get(hir_id);
    matches!(
        node,
        hir::Node::Item(hir::Item {
            kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
            ..
        })
    )
}

fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    is_const_fn(tcx, def_id)
        && match tcx.lookup_const_stability(def_id) {
            Some(stab) => {
                if cfg!(debug_assertions) && stab.promotable {
                    let sig = tcx.fn_sig(def_id);
                    assert_eq!(
                        sig.unsafety(),
                        hir::Unsafety::Normal,
                        "don't mark const unsafe fns as promotable",
                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                    );
                }
                stab.promotable
            }
            None => false,
        }
}

pub fn provide(providers: &mut Providers) {
    *providers = Providers {
        is_const_fn_raw,
        is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()),
        is_promotable_const_fn,
        ..*providers
    };
}
<commit_msg>remove now-unused 'is_min_const_fn'<commit_after>use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::hir::map::blocks::FnLikeNode;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use rustc_target::spec::abi::Abi;

/// Whether the `def_id` counts as const fn in your current crate, considering all active
/// feature gates
pub fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    tcx.is_const_fn_raw(def_id)
        && match is_unstable_const_fn(tcx, def_id) {
            Some(feature_name) => {
                // has a `rustc_const_unstable` attribute, check whether the user enabled the
                // corresponding feature gate.
                tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_name)
            }
            // functions without const stability are either stable user written
            // const fn or the user is using feature gates and we thus don't
            // care what they do
            None => true,
        }
}

/// Whether the `def_id` is an unstable const fn and what feature gate is necessary to enable it
pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
    if tcx.is_const_fn_raw(def_id) {
        let const_stab = tcx.lookup_const_stability(def_id)?;
        if const_stab.level.is_unstable() { Some(const_stab.feature) } else { None }
    } else {
        None
    }
}

pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
    let parent_id = tcx.hir().get_parent_did(hir_id);
    if !parent_id.is_top_level_module() { is_const_impl_raw(tcx, parent_id) } else { false }
}

/// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
/// said intrinsic has a `rustc_const_{un,}stable` attribute.
fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());

    let node = tcx.hir().get(hir_id);

    if let hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) =
        node
    {
        // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
        // foreign items cannot be evaluated at compile-time.
        if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = tcx.hir().get_foreign_abi(hir_id) {
            tcx.lookup_const_stability(def_id).is_some()
        } else {
            false
        }
    } else if let Some(fn_like) = FnLikeNode::from_node(node) {
        if fn_like.constness() == hir::Constness::Const {
            return true;
        }

        // If the function itself is not annotated with `const`, it may still be a `const fn`
        // if it resides in a const trait impl.
        is_parent_const_impl_raw(tcx, hir_id)
    } else if let hir::Node::Ctor(_) = node {
        true
    } else {
        false
    }
}

/// Checks whether the given item is an `impl` that has a `const` modifier.
fn is_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
    let node = tcx.hir().get(hir_id);
    matches!(
        node,
        hir::Node::Item(hir::Item {
            kind: hir::ItemKind::Impl(hir::Impl { constness: hir::Constness::Const, .. }),
            ..
        })
    )
}

fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
    is_const_fn(tcx, def_id)
        && match tcx.lookup_const_stability(def_id) {
            Some(stab) => {
                if cfg!(debug_assertions) && stab.promotable {
                    let sig = tcx.fn_sig(def_id);
                    assert_eq!(
                        sig.unsafety(),
                        hir::Unsafety::Normal,
                        "don't mark const unsafe fns as promotable",
                        // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                    );
                }
                stab.promotable
            }
            None => false,
        }
}

pub fn provide(providers: &mut Providers) {
    *providers = Providers {
        is_const_fn_raw,
        is_const_impl_raw: |tcx, def_id| is_const_impl_raw(tcx, def_id.expect_local()),
        is_promotable_const_fn,
        ..*providers
    };
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) 2014 Vsevolod Velichko <torkvemada@sorokdva.net>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) retcode

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use std::fs;
use std::path::{Path, PathBuf};
use uucore::fs::{canonicalize, CanonicalizeMode};

static ABOUT: &str = "print the resolved path";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_QUIET: &str = "quiet";
static OPT_STRIP: &str = "strip";
static OPT_ZERO: &str = "zero";

static ARG_FILES: &str = "files";

fn get_usage() -> String {
    format!("{0} [OPTION]... FILE...", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(OPT_QUIET)
                .short("q")
                .long(OPT_QUIET)
                .help("Do not print warnings for invalid paths"),
        )
        .arg(
            Arg::with_name(OPT_STRIP)
                .short("s")
                .long(OPT_STRIP)
                .help("Only strip '.' and '..' components, but don't resolve symbolic links"),
        )
        .arg(
            Arg::with_name(OPT_ZERO)
                .short("z")
                .long(OPT_ZERO)
                .help("Separate output filenames with \\0 rather than newline"),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .required(true)
                .min_values(1),
        )
        .get_matches_from(args);

    /*  the list of files */

    let paths: Vec<PathBuf> = matches
        .values_of(ARG_FILES)
        .unwrap()
        .map(PathBuf::from)
        .collect();

    let strip = matches.is_present(OPT_STRIP);
    let zero = matches.is_present(OPT_ZERO);
    let quiet = matches.is_present(OPT_QUIET);
    let mut retcode = 0;
    for path in &paths {
        if !resolve_path(path, strip, zero, quiet) {
            retcode = 1
        };
    }
    retcode
}

fn resolve_path(p: &Path, strip: bool, zero: bool, quiet: bool) -> bool {
    let abs = canonicalize(p, CanonicalizeMode::Normal).unwrap();

    if strip {
        if zero {
            print!("{}\0", p.display());
        } else {
            println!("{}", p.display())
        }
        return true;
    }

    let mut result = PathBuf::new();
    let mut links_left = 256;

    for part in abs.components() {
        result.push(part.as_os_str());
        loop {
            if links_left == 0 {
                if !quiet {
                    show_error!("Too many symbolic links: {}", p.display())
                };
                return false;
            }
            match fs::metadata(result.as_path()) {
                Err(_) => break,
                Ok(ref m) if !m.file_type().is_symlink() => break,
                Ok(_) => {
                    links_left -= 1;
                    match fs::read_link(result.as_path()) {
                        Ok(x) => {
                            result.pop();
                            result.push(x.as_path());
                        }
                        _ => {
                            if !quiet {
                                show_error!("Invalid path: {}", p.display())
                            };
                            return false;
                        }
                    }
                }
            }
        }
    }

    if zero {
        print!("{}\0", result.display());
    } else {
        println!("{}", result.display());
    }

    true
}
<commit_msg>realpath: use uucore::fs::canonicalize()<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) 2014 Vsevolod Velichko <torkvemada@sorokdva.net>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) retcode

#[macro_use]
extern crate uucore;

use clap::{App, Arg};
use std::path::{Path, PathBuf};
use uucore::fs::{canonicalize, CanonicalizeMode};

static ABOUT: &str = "print the resolved path";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_QUIET: &str = "quiet";
static OPT_STRIP: &str = "strip";
static OPT_ZERO: &str = "zero";

static ARG_FILES: &str = "files";

fn get_usage() -> String {
    format!("{0} [OPTION]... FILE...", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(OPT_QUIET)
                .short("q")
                .long(OPT_QUIET)
                .help("Do not print warnings for invalid paths"),
        )
        .arg(
            Arg::with_name(OPT_STRIP)
                .short("s")
                .long(OPT_STRIP)
                .help("Only strip '.' and '..' components, but don't resolve symbolic links"),
        )
        .arg(
            Arg::with_name(OPT_ZERO)
                .short("z")
                .long(OPT_ZERO)
                .help("Separate output filenames with \\0 rather than newline"),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .required(true)
                .min_values(1),
        )
        .get_matches_from(args);

    /*  the list of files */

    let paths: Vec<PathBuf> = matches
        .values_of(ARG_FILES)
        .unwrap()
        .map(PathBuf::from)
        .collect();

    let strip = matches.is_present(OPT_STRIP);
    let zero = matches.is_present(OPT_ZERO);
    let quiet = matches.is_present(OPT_QUIET);
    let mut retcode = 0;
    for path in &paths {
        if let Err(e) = resolve_path(path, strip, zero) {
            if !quiet {
                show_error!("{}: {}", e, path.display());
            }
            retcode = 1
        };
    }
    retcode
}

/// Resolve a path to an absolute form and print it.
///
/// If `strip` is `true`, then this function does not attempt to resolve
/// symbolic links in the path. If `zero` is `true`, then this function
/// prints the path followed by the null byte (`'\0'`) instead of a
/// newline character (`'\n'`).
///
/// # Errors
///
/// This function returns an error if there is a problem resolving
/// symbolic links.
fn resolve_path(p: &Path, strip: bool, zero: bool) -> std::io::Result<()> {
    let mode = if strip {
        CanonicalizeMode::None
    } else {
        CanonicalizeMode::Normal
    };
    let abs = canonicalize(p, mode)?;
    let line_ending = if zero { '\0' } else { '\n' };
    print!("{}{}", abs.display(), line_ending);
    Ok(())
}
<|endoftext|>


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

use crate::account_address::AccountAddress;
use libra_crypto::{ed25519::Ed25519PublicKey, x25519};
use libra_network_address::{encrypted::RawEncNetworkAddress, RawNetworkAddress};
use move_core_types::move_resource::MoveResource;
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
pub struct ValidatorConfigResource {
    pub validator_config: Option<ValidatorConfig>,
    pub delegated_account: Option<AccountAddress>,
    pub human_name: Vec<u8>,
}

impl MoveResource for ValidatorConfigResource {
    const MODULE_NAME: &'static str = "ValidatorConfig";
    const STRUCT_NAME: &'static str = "ValidatorConfig";
}

#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct ValidatorConfig {
    pub consensus_public_key: Ed25519PublicKey,
    pub validator_network_identity_public_key: x25519::PublicKey,
    pub validator_network_address: RawEncNetworkAddress,
    pub full_node_network_identity_public_key: x25519::PublicKey,
    pub full_node_network_address: RawNetworkAddress,
}

impl ValidatorConfig {
    pub fn new(
        consensus_public_key: Ed25519PublicKey,
        validator_network_identity_public_key: x25519::PublicKey,
        validator_network_address: RawEncNetworkAddress,
        full_node_network_identity_public_key: x25519::PublicKey,
        full_node_network_address: RawNetworkAddress,
    ) -> Self {
        ValidatorConfig {
            consensus_public_key,
            validator_network_identity_public_key,
            validator_network_address,
            full_node_network_identity_public_key,
            full_node_network_address,
        }
    }
}
<commit_msg>Add traits to ValidatorConfigResource<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_address::AccountAddress;
use libra_crypto::{ed25519::Ed25519PublicKey, x25519};
use libra_network_address::{encrypted::RawEncNetworkAddress, RawNetworkAddress};
use move_core_types::move_resource::MoveResource;
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq)]
pub struct ValidatorConfigResource {
    pub validator_config: Option<ValidatorConfig>,
    pub delegated_account: Option<AccountAddress>,
    pub human_name: Vec<u8>,
}

impl MoveResource for ValidatorConfigResource {
    const MODULE_NAME: &'static str = "ValidatorConfig";
    const STRUCT_NAME: &'static str = "ValidatorConfig";
}

#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct ValidatorConfig {
    pub consensus_public_key: Ed25519PublicKey,
    pub validator_network_identity_public_key: x25519::PublicKey,
    pub validator_network_address: RawEncNetworkAddress,
    pub full_node_network_identity_public_key: x25519::PublicKey,
    pub full_node_network_address: RawNetworkAddress,
}

impl ValidatorConfig {
    pub fn new(
        consensus_public_key: Ed25519PublicKey,
        validator_network_identity_public_key: x25519::PublicKey,
        validator_network_address: RawEncNetworkAddress,
        full_node_network_identity_public_key: x25519::PublicKey,
        full_node_network_address: RawNetworkAddress,
    ) -> Self {
        ValidatorConfig {
            consensus_public_key,
            validator_network_identity_public_key,
            validator_network_address,
            full_node_network_identity_public_key,
            full_node_network_address,
        }
    }
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};

use once_cell::sync::OnceCell;

use crate::context::Context;
use crate::lifecycle::GlobalCell;
use crate::result::NeonResult;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

fn next_id() -> usize {
    COUNTER.fetch_add(1, Ordering::SeqCst)
}

/// A cell that can be used to allocate data that is global to an instance
/// of a Neon addon.
#[derive(Default)]
pub struct Global<T> {
    _type: PhantomData<T>,
    id: OnceCell<usize>,
}

impl<T> Global<T> {
    /// Creates a new global value. This method is `const`, so it can be assigned to
    /// static variables.
    pub const fn new() -> Self {
        Default::default()
    }

    fn id(&self) -> usize {
        *self.id.get_or_init(next_id)
    }
}

impl<T: Any + Send + 'static> Global<T> {
    /// Gets the current value of the global. Returns `None` if the global has not
    /// yet been initialized.
    pub fn get<'cx, 'a, C>(&self, cx: &'a mut C) -> Option<&'cx T>
    where
        C: Context<'cx>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: Option<&T> =
            GlobalCell::get(cx, self.id()).map(|value| value.downcast_ref().unwrap());

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<Option<&'a T>, Option<&'cx T>>(r) }
    }

    /// Gets the current value of the global, initializing it with `value` if it has
    /// not yet been initialized.
    pub fn get_or_init<'cx, 'a, C>(&self, cx: &'a mut C, value: T) -> &'cx T
    where
        C: Context<'cx>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_init(cx, self.id(), Box::new(value))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the global, initializing it with the result of
    /// calling `f` if it has not yet been initialized.
    pub fn get_or_init_with<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> &'cx T
    where
        C: Context<'cx>,
        F: FnOnce() -> T,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_init_with(cx, self.id(), || Box::new(f()))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the global, initializing it with the result of
    /// calling `f` if it has not yet been initialized. Returns `Err` if the
    /// callback triggers a JavaScript exception.
    ///
    /// During the execution of `f`, calling any methods on this `Global` that
    /// attempt to initialize it will panic.
    pub fn get_or_try_init<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> NeonResult<&'cx T>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> NeonResult<T>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_try_init(cx, self.id(), |cx| Ok(Box::new(f(cx)?)))?
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        Ok(unsafe { std::mem::transmute::<&'a T, &'cx T>(r) })
    }
}

impl<T: Any + Send + Default + 'static> Global<T> {
    /// Gets the current value of the global, initializing it with the default value
    /// if it has not yet been initialized.
    pub fn get_or_init_default<'cx, 'a, C>(&self, cx: &'a mut C) -> &'cx T
    where
        C: Context<'cx>,
    {
        self.get_or_init_with(cx, Default::default)
    }
}
<commit_msg>Undo previous commit, which failed to type-check.<commit_after>use std::any::Any;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicUsize, Ordering};

use once_cell::sync::OnceCell;

use crate::context::Context;
use crate::lifecycle::GlobalCell;
use crate::result::NeonResult;

static COUNTER: AtomicUsize = AtomicUsize::new(0);

fn next_id() -> usize {
    COUNTER.fetch_add(1, Ordering::SeqCst)
}

/// A cell that can be used to allocate data that is global to an instance
/// of a Neon addon.
#[derive(Default)]
pub struct Global<T> {
    _type: PhantomData<T>,
    id: OnceCell<usize>,
}

impl<T> Global<T> {
    /// Creates a new global value. This method is `const`, so it can be assigned to
    /// static variables.
    pub const fn new() -> Self {
        Self {
            _type: PhantomData,
            id: OnceCell::new(),
        }
    }

    fn id(&self) -> usize {
        *self.id.get_or_init(next_id)
    }
}

impl<T: Any + Send + 'static> Global<T> {
    /// Gets the current value of the global. Returns `None` if the global has not
    /// yet been initialized.
    pub fn get<'cx, 'a, C>(&self, cx: &'a mut C) -> Option<&'cx T>
    where
        C: Context<'cx>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: Option<&T> =
            GlobalCell::get(cx, self.id()).map(|value| value.downcast_ref().unwrap());

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<Option<&'a T>, Option<&'cx T>>(r) }
    }

    /// Gets the current value of the global, initializing it with `value` if it has
    /// not yet been initialized.
    pub fn get_or_init<'cx, 'a, C>(&self, cx: &'a mut C, value: T) -> &'cx T
    where
        C: Context<'cx>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_init(cx, self.id(), Box::new(value))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the global, initializing it with the result of
    /// calling `f` if it has not yet been initialized.
    pub fn get_or_init_with<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> &'cx T
    where
        C: Context<'cx>,
        F: FnOnce() -> T,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_init_with(cx, self.id(), || Box::new(f()))
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        unsafe { std::mem::transmute::<&'a T, &'cx T>(r) }
    }

    /// Gets the current value of the global, initializing it with the result of
    /// calling `f` if it has not yet been initialized. Returns `Err` if the
    /// callback triggers a JavaScript exception.
    ///
    /// During the execution of `f`, calling any methods on this `Global` that
    /// attempt to initialize it will panic.
    pub fn get_or_try_init<'cx, 'a, C, F>(&self, cx: &'a mut C, f: F) -> NeonResult<&'cx T>
    where
        C: Context<'cx>,
        F: FnOnce(&mut C) -> NeonResult<T>,
    {
        // Safety: The type bound Global<T> and the fact that every Global has a unique
        // id guarantees that the cell is only ever assigned instances of type T.
        let r: &T = GlobalCell::get_or_try_init(cx, self.id(), |cx| Ok(Box::new(f(cx)?)))?
            .downcast_ref()
            .unwrap();

        // Safety: Since the Box is immutable and heap-allocated, it's guaranteed not to
        // move or change for the duration of the context.
        Ok(unsafe { std::mem::transmute::<&'a T, &'cx T>(r) })
    }
}

impl<T: Any + Send + Default + 'static> Global<T> {
    /// Gets the current value of the global, initializing it with the default value
    /// if it has not yet been initialized.
    pub fn get_or_init_default<'cx, 'a, C>(&self, cx: &'a mut C) -> &'cx T
    where
        C: Context<'cx>,
    {
        self.get_or_init_with(cx, Default::default)
    }
}
<|endoftext|>


<commit_before>use analysis::parameter::Parameter;
use env::Env;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SafetyAssertionMode {
    None,
    Skip,
    InMainThread,
}

impl Default for SafetyAssertionMode {
    fn default() -> SafetyAssertionMode {
        SafetyAssertionMode::None
    }
}

impl SafetyAssertionMode {
    pub fn of(env: &Env, params: &[Parameter]) -> SafetyAssertionMode {
        use self::SafetyAssertionMode::*;
        use library::Type::*;
        if !env.config.generate_safety_asserts {
            return None;
        }
        if params.len() > 0 && params[0].instance_parameter {
            return None;
        }
        for par in params {
            match *env.library.type_(par.typ) {
                Class(..) | Interface(..) if !*par.nullable
                    => return Skip,
                _ => (),
            }
        }

        InMainThread
    }
}
<commit_msg>Limit skipping only for types from current crate<commit_after>use analysis::parameter::Parameter;
use env::Env;
use library;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SafetyAssertionMode {
    None,
    Skip,
    InMainThread,
}

impl Default for SafetyAssertionMode {
    fn default() -> SafetyAssertionMode {
        SafetyAssertionMode::None
    }
}

impl SafetyAssertionMode {
    pub fn of(env: &Env, params: &[Parameter]) -> SafetyAssertionMode {
        use self::SafetyAssertionMode::*;
        use library::Type::*;
        if !env.config.generate_safety_asserts {
            return None;
        }
        if params.len() > 0 && params[0].instance_parameter {
            return None;
        }
        for par in params {
            match *env.library.type_(par.typ) {
                Class(..) | Interface(..) if !*par.nullable && par.typ.ns_id == library::MAIN_NAMESPACE
                    => return Skip,
                _ => (),
            }
        }

        InMainThread
    }
}
<|endoftext|>


<commit_before>//! Test command for verifying the unwind emitted for each function.
//!
//! The `unwind` test command runs each function through the full code generator pipeline.
#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]

use crate::subtest::{run_filecheck, Context, SubTest, SubtestResult};
use byteorder::{LittleEndian, ReadBytesExt};
use cranelift_codegen;
use cranelift_codegen::ir;
use cranelift_reader::TestCommand;
use std::borrow::Cow;
use std::fmt::Write;
use std::io::Cursor;

struct TestUnwind;

pub fn subtest(parsed: &TestCommand) -> SubtestResult<Box<dyn SubTest>> {
    assert_eq!(parsed.command, "unwind");
    if !parsed.options.is_empty() {
        Err(format!("No options allowed on {}", parsed))
    } else {
        Ok(Box::new(TestUnwind))
    }
}

impl SubTest for TestUnwind {
    fn name(&self) -> &'static str {
        "unwind"
    }

    fn is_mutating(&self) -> bool {
        false
    }

    fn needs_isa(&self) -> bool {
        true
    }

    fn run(&self, func: Cow<ir::Function>, context: &Context) -> SubtestResult<()> {
        let isa = context.isa.expect("unwind needs an ISA");
        let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());

        comp_ctx.compile(isa).expect("failed to compile function");

        let mut mem = Vec::new();
        comp_ctx.emit_unwind_info(isa, &mut mem);

        let mut text = String::new();
        if mem.is_empty() {
            writeln!(text, "No unwind information.").unwrap();
        } else {
            print_unwind_info(&mut text, &mem);
        }

        run_filecheck(&text, context)
    }
}

fn print_unwind_info(text: &mut String, mem: &[u8]) {
    let info = UnwindInfo::from_cursor(&mut Cursor::new(mem)).expect("failed to read unwind info");

    // Assert correct alignment and padding of the unwind information
    assert!(mem.len() % 4 == 0);
    assert_eq!(
        mem.len(),
        4 + ((info.unwind_code_count_raw as usize) * 2)
            + if (info.unwind_code_count_raw & 1) == 1 {
                2
            } else {
                0
            }
    );

    writeln!(text, "{:#?}", info).unwrap();
}

#[derive(Debug)]
struct UnwindInfo {
    pub version: u8,
    pub flags: u8,
    pub prologue_size: u8,
    pub unwind_code_count_raw: u8,
    pub frame_register: u8,
    pub frame_register_offset: u8,
    pub unwind_codes: Vec<UnwindCode>,
}

impl UnwindInfo {
    fn from_cursor(cursor: &mut Cursor<&[u8]>) -> std::io::Result<Self> {
        let version_and_flags = cursor.read_u8()?;
        let prologue_size = cursor.read_u8()?;
        let unwind_code_count_raw = cursor.read_u8()?;
        let frame_register_and_offset = cursor.read_u8()?;
        let mut unwind_codes = Vec::new();

        let mut i = 0;
        while i < unwind_code_count_raw {
            let code = UnwindCode::from_cursor(cursor)?;

            i += match &code.value {
                UnwindValue::None => 1,
                UnwindValue::U16(_) => 2,
                UnwindValue::U32(_) => 3,
            };

            unwind_codes.push(code);
        }

        Ok(Self {
            version: version_and_flags & 0x3,
            flags: (version_and_flags & 0xF8) >> 3,
            prologue_size,
            unwind_code_count_raw,
            frame_register: frame_register_and_offset & 0xF,
            frame_register_offset: (frame_register_and_offset & 0xF0) >> 4,
            unwind_codes,
        })
    }
}

#[derive(Debug)]
struct UnwindCode {
    pub offset: u8,
    pub op: UnwindOperation,
    pub info: u8,
    pub value: UnwindValue,
}

impl UnwindCode {
    fn from_cursor(cursor: &mut Cursor<&[u8]>) -> std::io::Result<Self> {
        let offset = cursor.read_u8()?;
        let op_and_info = cursor.read_u8()?;
        let op = UnwindOperation::from(op_and_info & 0xF);
        let info = (op_and_info & 0xF0) >> 4;

        let value = match op {
            UnwindOperation::LargeStackAlloc => match info {
                0 => UnwindValue::U16(cursor.read_u16::<LittleEndian>()?),
                1 => UnwindValue::U32(cursor.read_u32::<LittleEndian>()?),
                _ => panic!("unexpected stack alloc info value"),
            },
            UnwindOperation::SaveNonvolatileRegister => {
                UnwindValue::U16(cursor.read_u16::<LittleEndian>()?)
            }
            UnwindOperation::SaveNonvolatileRegisterFar => {
                UnwindValue::U32(cursor.read_u32::<LittleEndian>()?)
            }
            UnwindOperation::SaveXmm128 => UnwindValue::U16(cursor.read_u16::<LittleEndian>()?),
            UnwindOperation::SaveXmm128Far => UnwindValue::U32(cursor.read_u32::<LittleEndian>()?),
            _ => UnwindValue::None,
        };

        Ok(Self {
            offset,
            op,
            info,
            value,
        })
    }
}

#[derive(Debug)]
enum UnwindOperation {
    PushNonvolatileRegister,
    LargeStackAlloc,
    SmallStackAlloc,
    SetFramePointer,
    SaveNonvolatileRegister,
    SaveNonvolatileRegisterFar,
    SaveXmm128,
    SaveXmm128Far,
    PushMachineFrame,
}

impl From<u8> for UnwindOperation {
    fn from(value: u8) -> Self {
        // The numerical value is specified as part of the Windows x64 ABI
        match value {
            0 => Self::PushNonvolatileRegister,
            1 => Self::LargeStackAlloc,
            2 => Self::SmallStackAlloc,
            3 => Self::SetFramePointer,
            4 => Self::SaveNonvolatileRegister,
            5 => Self::SaveNonvolatileRegisterFar,
            6 => Self::SaveXmm128,
            7 => Self::SaveXmm128Far,
            8 => Self::PushMachineFrame,
            _ => panic!("unsupported unwind operation"),
        }
    }
}

#[derive(Debug)]
enum UnwindValue {
    None,
    U16(u16),
    U32(u32),
}
<commit_msg>Fix the cranelift-filetests build. (#1227)<commit_after>//! Test command for verifying the unwind emitted for each function.
//!
//! The `unwind` test command runs each function through the full code generator pipeline.
#![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_ptr_alignment))]

use crate::subtest::{run_filecheck, Context, SubTest, SubtestResult};
use byteorder::{ByteOrder, LittleEndian};
use cranelift_codegen;
use cranelift_codegen::ir;
use cranelift_reader::TestCommand;
use std::borrow::Cow;
use std::fmt::Write;

struct TestUnwind;

pub fn subtest(parsed: &TestCommand) -> SubtestResult<Box<dyn SubTest>> {
    assert_eq!(parsed.command, "unwind");
    if !parsed.options.is_empty() {
        Err(format!("No options allowed on {}", parsed))
    } else {
        Ok(Box::new(TestUnwind))
    }
}

impl SubTest for TestUnwind {
    fn name(&self) -> &'static str {
        "unwind"
    }

    fn is_mutating(&self) -> bool {
        false
    }

    fn needs_isa(&self) -> bool {
        true
    }

    fn run(&self, func: Cow<ir::Function>, context: &Context) -> SubtestResult<()> {
        let isa = context.isa.expect("unwind needs an ISA");
        let mut comp_ctx = cranelift_codegen::Context::for_function(func.into_owned());

        comp_ctx.compile(isa).expect("failed to compile function");

        let mut mem = Vec::new();
        comp_ctx.emit_unwind_info(isa, &mut mem);

        let mut text = String::new();
        if mem.is_empty() {
            writeln!(text, "No unwind information.").unwrap();
        } else {
            print_unwind_info(&mut text, &mem);
        }

        run_filecheck(&text, context)
    }
}

fn print_unwind_info(text: &mut String, mem: &[u8]) {
    let info = UnwindInfo::from_slice(mem);

    // Assert correct alignment and padding of the unwind information
    assert!(mem.len() % 4 == 0);
    assert_eq!(
        mem.len(),
        4 + ((info.unwind_code_count_raw as usize) * 2)
            + if (info.unwind_code_count_raw & 1) == 1 {
                2
            } else {
                0
            }
    );

    writeln!(text, "{:#?}", info).unwrap();
}

#[derive(Debug)]
struct UnwindInfo {
    pub version: u8,
    pub flags: u8,
    pub prologue_size: u8,
    pub unwind_code_count_raw: u8,
    pub frame_register: u8,
    pub frame_register_offset: u8,
    pub unwind_codes: Vec<UnwindCode>,
}

impl UnwindInfo {
    fn from_slice(mem: &[u8]) -> Self {
        let version_and_flags = mem[0];
        let prologue_size = mem[1];
        let unwind_code_count_raw = mem[2];
        let frame_register_and_offset = mem[3];
        let mut unwind_codes = Vec::new();

        let mut i = 0;
        while i < unwind_code_count_raw {
            let code = UnwindCode::from_slice(&mem[(4 + (i * 2) as usize)..]);

            i += match &code.value {
                UnwindValue::None => 1,
                UnwindValue::U16(_) => 2,
                UnwindValue::U32(_) => 3,
            };

            unwind_codes.push(code);
        }

        Self {
            version: version_and_flags & 0x3,
            flags: (version_and_flags & 0xF8) >> 3,
            prologue_size,
            unwind_code_count_raw,
            frame_register: frame_register_and_offset & 0xF,
            frame_register_offset: (frame_register_and_offset & 0xF0) >> 4,
            unwind_codes,
        }
    }
}

#[derive(Debug)]
struct UnwindCode {
    pub offset: u8,
    pub op: UnwindOperation,
    pub info: u8,
    pub value: UnwindValue,
}

impl UnwindCode {
    fn from_slice(mem: &[u8]) -> Self {
        let offset = mem[0];
        let op_and_info = mem[1];
        let op = UnwindOperation::from(op_and_info & 0xF);
        let info = (op_and_info & 0xF0) >> 4;

        let value = match op {
            UnwindOperation::LargeStackAlloc => match info {
                0 => UnwindValue::U16(LittleEndian::read_u16(&mem[2..])),
                1 => UnwindValue::U32(LittleEndian::read_u32(&mem[2..])),
                _ => panic!("unexpected stack alloc info value"),
            },
            UnwindOperation::SaveNonvolatileRegister => {
                UnwindValue::U16(LittleEndian::read_u16(&mem[2..]))
            }
            UnwindOperation::SaveNonvolatileRegisterFar => {
                UnwindValue::U32(LittleEndian::read_u32(&mem[2..]))
            }
            UnwindOperation::SaveXmm128 => UnwindValue::U16(LittleEndian::read_u16(&mem[2..])),
            UnwindOperation::SaveXmm128Far => UnwindValue::U32(LittleEndian::read_u32(&mem[2..])),
            _ => UnwindValue::None,
        };

        Self {
            offset,
            op,
            info,
            value,
        }
    }
}

#[derive(Debug)]
enum UnwindOperation {
    PushNonvolatileRegister,
    LargeStackAlloc,
    SmallStackAlloc,
    SetFramePointer,
    SaveNonvolatileRegister,
    SaveNonvolatileRegisterFar,
    SaveXmm128,
    SaveXmm128Far,
    PushMachineFrame,
}

impl From<u8> for UnwindOperation {
    fn from(value: u8) -> Self {
        // The numerical value is specified as part of the Windows x64 ABI
        match value {
            0 => Self::PushNonvolatileRegister,
            1 => Self::LargeStackAlloc,
            2 => Self::SmallStackAlloc,
            3 => Self::SetFramePointer,
            4 => Self::SaveNonvolatileRegister,
            5 => Self::SaveNonvolatileRegisterFar,
            6 => Self::SaveXmm128,
            7 => Self::SaveXmm128Far,
            8 => Self::PushMachineFrame,
            _ => panic!("unsupported unwind operation"),
        }
    }
}

#[derive(Debug)]
enum UnwindValue {
    None,
    U16(u16),
    U32(u32),
}
<|endoftext|>


<commit_before>//! Enhances `ide::LineIndex` with additional info required to convert offsets
//! into lsp positions.
//!
//! We maintain invariant that all internal strings use `\n` as line separator.
//! This module does line ending conversion and detection (so that we can
//! convert back to `\r\n` on the way out).

use std::sync::Arc;

pub enum PositionEncoding {
    Utf8,
    Utf16,
}

pub(crate) struct LineIndex {
    pub(crate) index: Arc<ide::LineIndex>,
    pub(crate) endings: LineEndings,
    pub(crate) encoding: PositionEncoding,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) enum LineEndings {
    Unix,
    Dos,
}

impl LineEndings {
    /// Replaces `\r\n` with `\n` in-place in `src`.
    pub(crate) fn normalize(src: String) -> (String, LineEndings) {
        if !src.as_bytes().contains(&b'\r') {
            return (src, LineEndings::Unix);
        }

        // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
        // While we *can* call `as_mut_vec` and do surgery on the live string
        // directly, let's rather steal the contents of `src`. This makes the code
        // safe even if a panic occurs.

        let mut buf = src.into_bytes();
        let mut gap_len = 0;
        let mut tail = buf.as_mut_slice();
        loop {
            let idx = match find_crlf(&tail[gap_len..]) {
                None => tail.len(),
                Some(idx) => idx + gap_len,
            };
            tail.copy_within(gap_len..idx, 0);
            tail = &mut tail[idx - gap_len..];
            if tail.len() == gap_len {
                break;
            }
            gap_len += 1;
        }

        // Account for removed `\r`.
        // After `set_len`, `buf` is guaranteed to contain utf-8 again.
        let new_len = buf.len() - gap_len;
        let src = unsafe {
            buf.set_len(new_len);
            String::from_utf8_unchecked(buf)
        };
        return (src, LineEndings::Dos);

        fn find_crlf(src: &[u8]) -> Option<usize> {
            src.windows(2).position(|it| it == b"\r\n")
        }
    }
}
<commit_msg>Add tests for LineEndings::normalize<commit_after>//! Enhances `ide::LineIndex` with additional info required to convert offsets
//! into lsp positions.
//!
//! We maintain invariant that all internal strings use `\n` as line separator.
//! This module does line ending conversion and detection (so that we can
//! convert back to `\r\n` on the way out).

use std::sync::Arc;

pub enum PositionEncoding {
    Utf8,
    Utf16,
}

pub(crate) struct LineIndex {
    pub(crate) index: Arc<ide::LineIndex>,
    pub(crate) endings: LineEndings,
    pub(crate) encoding: PositionEncoding,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) enum LineEndings {
    Unix,
    Dos,
}

impl LineEndings {
    /// Replaces `\r\n` with `\n` in-place in `src`.
    pub(crate) fn normalize(src: String) -> (String, LineEndings) {
        // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
        // While we *can* call `as_mut_vec` and do surgery on the live string
        // directly, let's rather steal the contents of `src`. This makes the code
        // safe even if a panic occurs.

        let mut buf = src.into_bytes();
        let mut gap_len = 0;
        let mut tail = buf.as_mut_slice();
        let mut crlf_seen = false;

        let find_crlf = |src: &[u8]| src.windows(2).position(|it| it == b"\r\n");

        loop {
            let idx = match find_crlf(&tail[gap_len..]) {
                None if crlf_seen => tail.len(),
                // SAFETY: buf is unchanged and therefor still contains utf8 data
                None => return (unsafe { String::from_utf8_unchecked(buf) }, LineEndings::Unix),
                Some(idx) => {
                    crlf_seen = true;
                    idx + gap_len
                }
            };
            tail.copy_within(gap_len..idx, 0);
            tail = &mut tail[idx - gap_len..];
            if tail.len() == gap_len {
                break;
            }
            gap_len += 1;
        }

        // Account for removed `\r`.
        // After `set_len`, `buf` is guaranteed to contain utf-8 again.
        let src = unsafe {
            let new_len = buf.len() - gap_len;
            buf.set_len(new_len);
            String::from_utf8_unchecked(buf)
        };
        (src, LineEndings::Dos)
    }
}

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

    #[test]
    fn unix() {
        let src = "a\nb\nc\n\n\n\n";
        let (res, endings) = LineEndings::normalize(src.into());
        assert_eq!(endings, LineEndings::Unix);
        assert_eq!(res, src);
    }

    #[test]
    fn dos() {
        let src = "\r\na\r\n\r\nb\r\nc\r\n\r\n\r\n\r\n";
        let (res, endings) = LineEndings::normalize(src.into());
        assert_eq!(endings, LineEndings::Dos);
        assert_eq!(res, "\na\n\nb\nc\n\n\n\n");
    }

    #[test]
    fn mixed() {
        let src = "a\r\nb\r\nc\r\n\n\r\n\n";
        let (res, endings) = LineEndings::normalize(src.into());
        assert_eq!(endings, LineEndings::Dos);
        assert_eq!(res, "a\nb\nc\n\n\n\n");
    }

    #[test]
    fn none() {
        let src = "abc";
        let (res, endings) = LineEndings::normalize(src.into());
        assert_eq!(endings, LineEndings::Unix);
        assert_eq!(res, src);
    }
}
<|endoftext|>


<commit_before>use core::hint;

/// Tock programs' entry point. Called by the kernel at program start. Sets up
/// the stack then calls rust_start() for the remainder of setup.
#[doc(hidden)]
#[naked]
#[no_mangle]
#[link_section = ".start"]
// The args for this function are:
//    app_start: usize,
//    mem_start: usize,
//    memory_len: usize,
//    app_heap_break: usize,
// Due to Rust issue: https://github.com/rust-lang/rust/issues/42779 we can't have
// args to the function
pub unsafe extern "C" fn _start() -> ! {
    asm!(
    // Compute the stack top.
    //
    // struct hdr* myhdr = (struct hdr*) app_start;
    // uint32_t stacktop = (((uint32_t) mem_start + myhdr->stack_size + 7) & 0xfffffff8);
    "lw   t0, 36(a0)         // t0 = myhdr->stack_size
    addi t0, t0, 7          // t0 = myhdr->stack_size + 7
    add  t0, t0, a1         // t0 = mem_start + myhdr->stack_size + 7
    li   t1, 7              // t1 = 7
    not  t1, t1             // t1 = ~0x7
    and  t0, t0, t1         // t0 = (mem_start + myhdr->stack_size + 7) & ~0x7
    //
    // Compute the app data size and where initial app brk should go.
    // This includes the GOT, data, and BSS sections. However, we can't be sure
    // the linker puts them back-to-back, but we do assume that BSS is last
    // (i.e. myhdr->got_start < myhdr->bss_start && myhdr->data_start <
    // myhdr->bss_start). With all of that true, then the size is equivalent
    // to the end of the BSS section.
    //
    // uint32_t appdata_size = myhdr->bss_start + myhdr->bss_size;
    lw   t1, 24(a0)         // t1 = myhdr->bss_start
    lw   t2, 28(a0)         // t2 = myhdr->bss_size
    lw   t3,  4(a0)         // t3 = myhdr->got_start
    add  t1, t1, t2         // t1 = bss_start + bss_size
    //
    // Move arguments we need to keep over to callee-saved locations.
    mv   s0, a0             // s0 = void* app_start
    mv   s1, t0             // s1 = stack_top
    mv   s2, a3             // s2 = app_heap_break
    //
    // Now we may want to move the stack pointer. If the kernel set the
    // `app_heap_break` larger than we need (and we are going to call `brk()`
    // to reduce it) then our stack pointer will fit and we can move it now.
    // Otherwise after the first syscall (the memop to set the brk), the return
    // will use a stack that is outside of the process accessible memory.
    //
    add t2, t0, t1          // t2 = stacktop + appdata_size
    bgt t2, a3, skip_set_sp // Compare `app_heap_break` with new brk.
                                // If our current `app_heap_break` is larger
                                // then we need to move the stack pointer
                                // before we call the `brk` syscall.
    mv  sp, t0              // Update the stack pointer

    skip_set_sp:            // Back to regularly scheduled programming.

    // Call `brk` to set to requested memory

    // memop(0, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 0               // a1 = 0
    mv  a2, t2              // a2 = stacktop + appdata_size
    ecall                   // memop
    //
    // Debug support, tell the kernel the stack location
    //
    // memop(10, stacktop);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 10              // a1 = 10
    mv  a2, s1              // a2 = stacktop
    ecall                   // memop
    //
    // Debug support, tell the kernel the heap location
    //
    // memop(11, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 11              // a1 = 10
    mv  a2, t2              // a2 = stacktop + appdata_size
    ecall                   // memop
    //
    // Setup initial stack pointer for normal execution
    // Call into the rest of startup. This should never return.
    mv   sp, s1             // sp = stacktop
    mv   a0, s0             // first arg is app_start
    mv   s0, sp             // Set the frame pointer to sp.
    mv   a1, s1             // second arg is stacktop
    mv   a2, s2             // third arg is app_heap_break
    jal  rust_start"
    :                                                              // No output operands
    :
    : "memory", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
      "x5", "x6", "x7", "x28", "x29", "x30", "x31", "x1"           // Clobbers
    : "volatile"                                                   // Options
    );
    hint::unreachable_unchecked();
}

/// Ensure an abort symbol exists.
#[cfg(target_arch = "riscv32")]
#[link_section = ".start"]
#[export_name = "abort"]
pub extern "C" fn abort() {
    unsafe {
        asm! ("
            // Simply go back to the start as if we had just booted.
            j    _start
        "
        :
        :
        :
        : "volatile");
    }
}
<commit_msg>Use the absolute addresses for calculation in entry assembly<commit_after>use core::hint;

/// Tock programs' entry point. Called by the kernel at program start. Sets up
/// the stack then calls rust_start() for the remainder of setup.
#[doc(hidden)]
#[naked]
#[no_mangle]
#[link_section = ".start"]
// The args for this function are:
//    app_start: usize,
//    mem_start: usize,
//    memory_len: usize,
//    app_heap_break: usize,
// Due to Rust issue: https://github.com/rust-lang/rust/issues/42779 we can't have
// args to the function
pub unsafe extern "C" fn _start() -> ! {
    asm!(
    // Compute the stack top.
    //
    // struct hdr* myhdr = (struct hdr*) app_start;
    // uint32_t stacktop = (((uint32_t) mem_start + myhdr->stack_size + 7) & 0xfffffff8);
    "lw   t0, 36(a0)         // t0 = myhdr->stack_size
    addi t0, t0, 7          // t0 = myhdr->stack_size + 7
    add  t0, t0, a1         // t0 = mem_start + myhdr->stack_size + 7
    li   t1, 7              // t1 = 7
    not  t1, t1             // t1 = ~0x7
    and  t0, t0, t1         // t0 = (mem_start + myhdr->stack_size + 7) & ~0x7
    //
    // Compute the app data size and where initial app brk should go.
    // This includes the GOT, data, and BSS sections. However, we can't be sure
    // the linker puts them back-to-back, but we do assume that BSS is last
    // (i.e. myhdr->got_start < myhdr->bss_start && myhdr->data_start <
    // myhdr->bss_start). With all of that true, then the size is equivalent
    // to the end of the BSS section.
    //
    // uint32_t appdata_size = myhdr->bss_start + myhdr->bss_size;
    lw   t1, 24(a0)         // t1 = myhdr->bss_start
    lw   t2, 28(a0)         // t2 = myhdr->bss_size
    lw   t3,  4(a0)         // t3 = myhdr->got_start
    add  t1, t1, t2         // t1 = bss_start + bss_size
    //
    // Move arguments we need to keep over to callee-saved locations.
    mv   s0, a0             // s0 = void* app_start
    mv   s1, t0             // s1 = stack_top
    mv   s2, a3             // s2 = app_heap_break
    //
    // Now we may want to move the stack pointer. If the kernel set the
    // `app_heap_break` larger than we need (and we are going to call `brk()`
    // to reduce it) then our stack pointer will fit and we can move it now.
    // Otherwise after the first syscall (the memop to set the brk), the return
    // will use a stack that is outside of the process accessible memory.
    //
    bgt t1, a3, skip_set_sp // Compare `app_heap_break` with new brk.
                                // If our current `app_heap_break` is larger
                                // then we need to move the stack pointer
                                // before we call the `brk` syscall.
    mv  sp, t0              // Update the stack pointer

    skip_set_sp:            // Back to regularly scheduled programming.

    // Call `brk` to set to requested memory

    // memop(0, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 0               // a1 = 0
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Debug support, tell the kernel the stack location
    //
    // memop(10, stacktop);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 10              // a1 = 10
    mv  a2, s1              // a2 = stacktop
    ecall                   // memop
    //
    // Debug support, tell the kernel the heap location
    //
    // memop(11, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 11              // a1 = 10
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Setup initial stack pointer for normal execution
    // Call into the rest of startup. This should never return.
    mv   sp, s1             // sp = stacktop
    mv   a0, s0             // first arg is app_start
    mv   s0, sp             // Set the frame pointer to sp.
    mv   a1, s1             // second arg is stacktop
    mv   a2, s2             // third arg is app_heap_break
    jal  rust_start"
    :                                                              // No output operands
    :
    : "memory", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
      "x5", "x6", "x7", "x28", "x29", "x30", "x31", "x1"           // Clobbers
    : "volatile"                                                   // Options
    );
    hint::unreachable_unchecked();
}

/// Ensure an abort symbol exists.
#[cfg(target_arch = "riscv32")]
#[link_section = ".start"]
#[export_name = "abort"]
pub extern "C" fn abort() {
    unsafe {
        asm! ("
            // Simply go back to the start as if we had just booted.
            j    _start
        "
        :
        :
        :
        : "volatile");
    }
}
<|endoftext|>