<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
use std::collections::HashMap;
use std::io;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;

pub enum Message {
    Request(Request),
    Notification(Notification),
}

pub struct ResponseHandle {
    id: Id,
    writer: Arc<Mutex<Write + Send>>,
}

impl ResponseHandle {
    pub fn respond(self, response: Result<serde_json::Value, serde_json::Value>) {
        self.writer
            .lock()
            .unwrap()
            .write_packet(match response {
                Ok(result) => {
                    json!({ "jsonrpc": "2.0", "id": self.id, "result": result}).to_string()
                }
                Err(error) => json!({ "jsonrpc": "2.0", "id": self.id, "error": error}).to_string(),
            })
            .unwrap();
    }
}

pub struct Request {
    pub method: String,
    pub params: serde_json::Value,
    pub response_handle: ResponseHandle,
}

pub struct Notification {
    pub method: String,
    pub params: serde_json::Value,
}

type ResultOrError = Result<serde_json::Value, serde_json::Value>;
type MyMap = HashMap<Id, Sender<ResultOrError>>;

// Basic implementation of LSP Server.
//
// It exists after receiving `exit` notification and forwards all other requests and responses to
// handler passed in run method.
pub struct Server<R: Read, W: Write> {
    reader: R,
    writer: Arc<Mutex<W>>,
    // Map of requests that are currently waiting for the response from client.
    running_requests: Arc<Mutex<MyMap>>,
}

#[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize)]
#[serde(untagged)]
enum Id {
    Number(i64),
    String(String),
}

impl<R, W> Iterator for Server<R, W>
where
    R: Read,
    W: Write + Send + 'static,
{
    type Item = Message;

    fn next(&mut self) -> Option<Message> {
        loop {
            let packet = match self.reader.read_packet() {
                Ok(packet) => packet,
                // TODO: Save the error
                Err(_) => return None,
            };
            let json: serde_json::Value = match serde_json::from_str(&packet) {
                Ok(value) => value,
                // TODO: We should probably reply with error?
                Err(_) => return None,
            };
            match &json {
                serde_json::Value::Object(map) => {
                    if let Some(serde_json::Value::String(method)) = map.get("method") {
                        if method == "exit" {
                            return None;
                        }
                        if let Some(id_val) = map.get("id") {
                            let id: Id = serde_json::from_value(id_val.clone()).unwrap();
                            return Some(Message::Request(Request {
                                method: method.to_string(),
                                params: json["params"].clone(),
                                response_handle: ResponseHandle {
                                    id: id,
                                    writer: self.writer.clone(),
                                },
                            }));
                        }
                        return Some(Message::Notification(Notification {
                            method: method.to_string(),
                            params: json["params"].clone(),
                        }));
                    }
                    if let Some(result) = map.get("result") {
                        if let Some(id_val) = map.get("id") {
                            let id: Id = serde_json::from_value(id_val.clone()).unwrap();
                            self.running_requests.lock().unwrap()[&id]
                                .send(Ok(result.clone()))
                                .unwrap();
                            continue;
                        }
                    }
                    // TODO: I think we should just respond with error here.
                    return None;
                }
                // TODO: I think we should just respond with error here.
                _ => return None,
            }
        }
    }
}

impl<R, W> Server<R, W>
where
    R: Read,
    W: Write + Send + 'static,
{
    pub fn new(reader: R, writer: W) -> Server<R, W> {
        return Server {
            reader: reader,
            writer: Arc::new(Mutex::new(writer)),
            running_requests: Arc::new(Mutex::new(HashMap::new())),
        };
    }

    pub fn sender(&self) -> MySender {
        return MySender {
            next_id: Arc::new(Mutex::new(Counter::new())),
            writer: self.writer.clone(),
            running_requests: Arc::downgrade(&self.running_requests),
        };
    }
}

struct Counter {
    id: i64,
}

impl Counter {
    fn new() -> Counter {
        Counter { id: 0 }
    }

    fn next(&mut self) -> i64 {
        self.id += 1;
        return self.id;
    }
}

pub struct MySender {
    next_id: Arc<Mutex<Counter>>,
    writer: Arc<Mutex<Write + Send>>,
    running_requests: Weak<Mutex<MyMap>>,
}

impl MySender {
    pub fn send_notification(&self, method: &str, params: serde_json::Value) {
        // TODO: how to properly handle errors here?
        self.writer
            .lock()
            .unwrap()
            .write_packet(
                json!(
                {
                    "jsonrpc": "2.0",
                    "method": method,
                    "params": params}
                )
                .to_string(),
            )
            .unwrap();
    }

    pub fn send_request(
        &self,
        method: &str,
        params: serde_json::Value,
    ) -> Result<serde_json::Value, serde_json::Value> {
        let running_requests = match self.running_requests.upgrade() {
            Some(x) => x,
            None => panic!("failed to upgrade running_requests"),
        };
        let id: Id = Id::Number(self.next_id.lock().unwrap().next());
        let (sender, receiver) = channel();
        running_requests.lock().unwrap().insert(id.clone(), sender);
        // TODO: how to properly handle errors here?
        self.writer
            .lock()
            .unwrap()
            .write_packet(
                json!(
                {
                    "jsonrpc": "2.0",
                    "id": id,
                    "method": method,
                    "params": params}
                )
                .to_string(),
            )
            .unwrap();
        return receiver.recv().unwrap();
    }
}

pub trait Read {
    fn read_packet(&mut self) -> Result<String, io::Error>;
}

pub trait Write {
    fn write_packet(&self, packet: String) -> Result<(), io::Error>;
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::mpsc::Receiver;

    struct FakeReader {
        receiver: Receiver<String>,
    }

    impl FakeReader {
        fn new() -> (Sender<String>, FakeReader) {
            let (sender, receiver) = channel();
            return (sender, FakeReader { receiver: receiver });
        }
    }

    impl Read for FakeReader {
        fn read_packet(&mut self) -> Result<String, io::Error> {
            self.receiver
                .recv()
                .map_err(|_| io::Error::new(io::ErrorKind::UnexpectedEof, "EOF encountered"))
        }
    }
    struct FakeWriter {
        sender: Sender<String>,
    }

    impl FakeWriter {
        fn new() -> (Receiver<String>, FakeWriter) {
            let (sender, receiver) = channel();
            return (receiver, FakeWriter { sender: sender });
        }
    }

    impl Write for FakeWriter {
        fn write_packet(&self, packet: String) -> Result<(), io::Error> {
            self.sender.send(packet).unwrap();
            Ok(())
        }
    }

    struct Client {
        sender: Sender<String>,
        receiver: Receiver<String>,
    }

    impl Client {
        fn recv(&self) -> Result<serde_json::Value, ()> {
            Ok(self.receiver.recv().unwrap().parse().unwrap())
        }
        fn send(&self, req: serde_json::Value) -> Result<(), ()> {
            self.sender.send(req.to_string()).unwrap();
            Ok(())
        }
    }

    fn create_client_and_server() -> (Client, Server<FakeReader, FakeWriter>) {
        let (writer_ch, writer) = FakeWriter::new();
        let (reader_ch, reader) = FakeReader::new();
        let client = Client {
            sender: reader_ch,
            receiver: writer_ch,
        };
        let server = Server::new(reader, writer);
        return (client, server);
    }

    #[test]
    fn server_exits_after_exit_notification() {
        let (client, server) = create_client_and_server();
        client
            .send(json!({
                "jsonrpc": "2.0",
                "method": "exit",
            }))
            .unwrap();

        assert_eq!(server.count(), 0);
    }

    #[test]
    fn server_exits_when_reader_returns_eof() {
        let (client, server) = create_client_and_server();
        std::mem::drop(client);

        assert_eq!(server.count(), 0);
    }

    #[test]
    fn server_receives_notifications() {
        let notification = json!({
            "jsonrpc": "2.0",
            "method": "someMethod",
            "params": {
                "key": "value",
            }
        });
        let (client, mut server) = create_client_and_server();

        client.send(notification.clone()).unwrap();
        client
            .send(json!({
                "jsonrpc": "2.0",
                "method": "exit",
            }))
            .unwrap();

        let message = match server.next() {
            Some(message) => message,
            None => panic!("expected message, got None"),
        };
        match message {
            Message::Notification(n) => {
                assert_eq!(n.method, "someMethod");
                assert_eq!(n.params, json!({"key": "value"}));
            }
            _ => panic!("invalid message received, want notification"),
        }
    }

    #[test]
    fn server_receives_requests() {
        let request = json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "someMethod",
            "params": {
                "key": "value",
            }
        });
        let (client, mut server) = create_client_and_server();

        client.send(request.clone()).unwrap();
        client
            .send(json!({
                "jsonrpc": "2.0",
                "method": "exit",
            }))
            .unwrap();

        let message = match server.next() {
            Some(message) => message,
            None => panic!("expected message, got None"),
        };
        match message {
            Message::Request(r) => {
                assert_eq!(r.method, "someMethod");
                assert_eq!(r.params, json!({"key": "value"}));
                r.response_handle.respond(Ok(json!({"my": "response"})));
            }
            _ => panic!("invalid message received, want request"),
        }
        assert_eq!(
            client.recv().unwrap(),
            json!({
                "jsonrpc": "2.0",
                "id": 1,
                "result": {
                    "my": "response",
                }
            })
        )
    }

    #[test]
    fn server_can_send_notifications() {
        let (client, server) = create_client_and_server();

        server
            .sender()
            .send_notification("someMethod", json!({"key": "value"}));

        assert_eq!(
            client.recv().unwrap(),
            json!({
                "jsonrpc": "2.0",
                "method": "someMethod",
                "params": {
                    "key": "value",
                }} )
        );
    }

    #[test]
    fn server_can_send_requests() {
        let (client, server) = create_client_and_server();

        let sender = server.sender();

        let t = std::thread::spawn(move || {
            let res = sender
                .send_request("someMethod", json!({"key": "value"}))
                .unwrap();
            assert_eq!(res, json!({"key1": "value1"}));
        });
        let t2 = std::thread::spawn(move || {
            // Just consume all items.
            server.count();
        });

        assert_eq!(
            client.recv().unwrap(),
            json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "someMethod",
            "params": {
                "key": "value",
            }})
        );
        client
            .send(json!({
                "jsonrpc": "2.0",
                "id": 1,
                "result": {
                    "key1": "value1",
                }
            }))
            .unwrap();
        client
            .send(json!({
                "jsonrpc": "2.0",
                "method": "exit",
            }))
            .unwrap();

        t.join().unwrap();
        t2.join().unwrap();
    }
}
<commit_msg>Add `dyn` to traits in server module.<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use serde::Deserialize;
use serde::Serialize;
use serde_json::json;
use std::collections::HashMap;
use std::io;
use std::sync::mpsc::channel;
use std::sync::mpsc::Sender;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::Weak;

pub enum Message {
    Request(Request),
    Notification(Notification),
}

pub struct ResponseHandle {
    id: Id,
    writer: Arc<Mutex<dyn Write + Send>>,
}

impl ResponseHandle {
    pub fn respond(self, response: Result<serde_json::Value, serde_json::Value>) {
        self.writer
            .lock()
            .unwrap()
            .write_packet(match response {
                Ok(result) => {
                    json!({ "jsonrpc": "2.0", "id": self.id, "result": result}).to_string()
                }
                Err(error) => json!({ "jsonrpc": "2.0", "id": self.id, "error": error}).to_string(),
            })
            .unwrap();
    }
}

pub struct Request {
    pub method: String,
    pub params: serde_json::Value,
    pub response_handle: ResponseHandle,
}

pub struct Notification {
    pub method: String,
    pub params: serde_json::Value,
}

type ResultOrError = Result<serde_json::Value, serde_json::Value>;
type MyMap = HashMap<Id, Sender<ResultOrError>>;

// Basic implementation of LSP Server.
//
// It exists after receiving `exit` notification and forwards all other requests and responses to
// handler passed in run method.
pub struct Server<R: Read, W: Write> {
    reader: R,
    writer: Arc<Mutex<W>>,
    // Map of requests that are currently waiting for the response from client.
    running_requests: Arc<Mutex<MyMap>>,
}

#[derive(Debug, PartialEq, Clone, Hash, Eq, Deserialize, Serialize)]
#[serde(untagged)]
enum Id {
    Number(i64),
    String(String),
}

impl<R, W> Iterator for Server<R, W>
where
    R: Read,
    W: Write + Send + 'static,
{
    type Item = Message;

    fn next(&mut self) -> Option<Message> {
        loop {
            let packet = match self.reader.read_packet() {
                Ok(packet) => packet,
                // TODO: Save the error
                Err(_) => return None,
            };
            let json: serde_json::Value = match serde_json::from_str(&packet) {
                Ok(value) => value,
                // TODO: We should probably reply with error?
                Err(_) => return None,
            };
            match &json {
                serde_json::Value::Object(map) => {
                    if let Some(serde_json::Value::String(method)) = map.get("method") {
                        if method == "exit" {
                            return None;
                        }
                        if let Some(id_val) = map.get("id") {
                            let id: Id = serde_json::from_value(id_val.clone()).unwrap();
                            return Some(Message::Request(Request {
                                method: method.to_string(),
                                params: json["params"].clone(),
                                response_handle: ResponseHandle {
                                    id: id,
                                    writer: self.writer.clone(),
                                },
                            }));
                        }
                        return Some(Message::Notification(Notification {
                            method: method.to_string(),
                            params: json["params"].clone(),
                        }));
                    }
                    if let Some(result) = map.get("result") {
                        if let Some(id_val) = map.get("id") {
                            let id: Id = serde_json::from_value(id_val.clone()).unwrap();
                            self.running_requests.lock().unwrap()[&id]
                                .send(Ok(result.clone()))
                                .unwrap();
                            continue;
                        }
                    }
                    // TODO: I think we should just respond with error here.
                    return None;
                }
                // TODO: I think we should just respond with error here.
                _ => return None,
            }
        }
    }
}

impl<R, W> Server<R, W>
where
    R: Read,
    W: Write + Send + 'static,
{
    pub fn new(reader: R, writer: W) -> Server<R, W> {
        return Server {
            reader: reader,
            writer: Arc::new(Mutex::new(writer)),
            running_requests: Arc::new(Mutex::new(HashMap::new())),
        };
    }

    pub fn sender(&self) -> MySender {
        return MySender {
            next_id: Arc::new(Mutex::new(Counter::new())),
            writer: self.writer.clone(),
            running_requests: Arc::downgrade(&self.running_requests),
        };
    }
}

struct Counter {
    id: i64,
}

impl Counter {
    fn new() -> Counter {
        Counter { id: 0 }
    }

    fn next(&mut self) -> i64 {
        self.id += 1;
        return self.id;
    }
}

pub struct MySender {
    next_id: Arc<Mutex<Counter>>,
    writer: Arc<Mutex<dyn Write + Send>>,
    running_requests: Weak<Mutex<MyMap>>,
}

impl MySender {
    pub fn send_notification(&self, method: &str, params: serde_json::Value) {
        // TODO: how to properly handle errors here?
        self.writer
            .lock()
            .unwrap()
            .write_packet(
                json!(
                {
                    "jsonrpc": "2.0",
                    "method": method,
                    "params": params}
                )
                .to_string(),
            )
            .unwrap();
    }

    pub fn send_request(
        &self,
        method: &str,
        params: serde_json::Value,
    ) -> Result<serde_json::Value, serde_json::Value> {
        let running_requests = match self.running_requests.upgrade() {
            Some(x) => x,
            None => panic!("failed to upgrade running_requests"),
        };
        let id: Id = Id::Number(self.next_id.lock().unwrap().next());
        let (sender, receiver) = channel();
        running_requests.lock().unwrap().insert(id.clone(), sender);
        // TODO: how to properly handle errors here?
        self.writer
            .lock()
            .unwrap()
            .write_packet(
                json!(
                {
                    "jsonrpc": "2.0",
                    "id": id,
                    "method": method,
                    "params": params}
                )
                .to_string(),
            )
            .unwrap();
        return receiver.recv().unwrap();
    }
}

pub trait Read {
    fn read_packet(&mut self) -> Result<String, io::Error>;
}

pub trait Write {
    fn write_packet(&self, packet: String) -> Result<(), io::Error>;
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::mpsc::Receiver;

    struct FakeReader {
        receiver: Receiver<String>,
    }

    impl FakeReader {
        fn new() -> (Sender<String>, FakeReader) {
            let (sender, receiver) = channel();
            return (sender, FakeReader { receiver: receiver });
        }
    }

    impl Read for FakeReader {
        fn read_packet(&mut self) -> Result<String, io::Error> {
            self.receiver
                .recv()
                .map_err(|_| io::Error::new(io::ErrorKind::UnexpectedEof, "EOF encountered"))
        }
    }
    struct FakeWriter {
        sender: Sender<String>,
    }

    impl FakeWriter {
        fn new() -> (Receiver<String>, FakeWriter) {
            let (sender, receiver) = channel();
            return (receiver, FakeWriter { sender: sender });
        }
    }

    impl Write for FakeWriter {
        fn write_packet(&self, packet: String) -> Result<(), io::Error> {
            self.sender.send(packet).unwrap();
            Ok(())
        }
    }

    struct Client {
        sender: Sender<String>,
        receiver: Receiver<String>,
    }

    impl Client {
        fn recv(&self) -> Result<serde_json::Value, ()> {
            Ok(self.receiver.recv().unwrap().parse().unwrap())
        }
        fn send(&self, req: serde_json::Value) -> Result<(), ()> {
            self.sender.send(req.to_string()).unwrap();
            Ok(())
        }
    }

    fn create_client_and_server() -> (Client, Server<FakeReader, FakeWriter>) {
        let (writer_ch, writer) = FakeWriter::new();
        let (reader_ch, reader) = FakeReader::new();
        let client = Client {
            sender: reader_ch,
            receiver: writer_ch,
        };
        let server = Server::new(reader, writer);
        return (client, server);
    }

    #[test]
    fn server_exits_after_exit_notification() {
        let (client, server) = create_client_and_server();
        client
            .send(json!({
                "jsonrpc": "2.0",
                "method": "exit",
            }))
            .unwrap();

        assert_eq!(server.count(), 0);
    }

    #[test]
    fn server_exits_when_reader_returns_eof() {
        let (client, server) = create_client_and_server();
        std::mem::drop(client);

        assert_eq!(server.count(), 0);
    }

    #[test]
    fn server_receives_notifications() {
        let notification = json!({
            "jsonrpc": "2.0",
            "method": "someMethod",
            "params": {
                "key": "value",
            }
        });
        let (client, mut server) = create_client_and_server();

        client.send(notification.clone()).unwrap();
        client
            .send(json!({
                "jsonrpc": "2.0",
                "method": "exit",
            }))
            .unwrap();

        let message = match server.next() {
            Some(message) => message,
            None => panic!("expected message, got None"),
        };
        match message {
            Message::Notification(n) => {
                assert_eq!(n.method, "someMethod");
                assert_eq!(n.params, json!({"key": "value"}));
            }
            _ => panic!("invalid message received, want notification"),
        }
    }

    #[test]
    fn server_receives_requests() {
        let request = json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "someMethod",
            "params": {
                "key": "value",
            }
        });
        let (client, mut server) = create_client_and_server();

        client.send(request.clone()).unwrap();
        client
            .send(json!({
                "jsonrpc": "2.0",
                "method": "exit",
            }))
            .unwrap();

        let message = match server.next() {
            Some(message) => message,
            None => panic!("expected message, got None"),
        };
        match message {
            Message::Request(r) => {
                assert_eq!(r.method, "someMethod");
                assert_eq!(r.params, json!({"key": "value"}));
                r.response_handle.respond(Ok(json!({"my": "response"})));
            }
            _ => panic!("invalid message received, want request"),
        }
        assert_eq!(
            client.recv().unwrap(),
            json!({
                "jsonrpc": "2.0",
                "id": 1,
                "result": {
                    "my": "response",
                }
            })
        )
    }

    #[test]
    fn server_can_send_notifications() {
        let (client, server) = create_client_and_server();

        server
            .sender()
            .send_notification("someMethod", json!({"key": "value"}));

        assert_eq!(
            client.recv().unwrap(),
            json!({
                "jsonrpc": "2.0",
                "method": "someMethod",
                "params": {
                    "key": "value",
                }} )
        );
    }

    #[test]
    fn server_can_send_requests() {
        let (client, server) = create_client_and_server();

        let sender = server.sender();

        let t = std::thread::spawn(move || {
            let res = sender
                .send_request("someMethod", json!({"key": "value"}))
                .unwrap();
            assert_eq!(res, json!({"key1": "value1"}));
        });
        let t2 = std::thread::spawn(move || {
            // Just consume all items.
            server.count();
        });

        assert_eq!(
            client.recv().unwrap(),
            json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "someMethod",
            "params": {
                "key": "value",
            }})
        );
        client
            .send(json!({
                "jsonrpc": "2.0",
                "id": 1,
                "result": {
                    "key1": "value1",
                }
            }))
            .unwrap();
        client
            .send(json!({
                "jsonrpc": "2.0",
                "method": "exit",
            }))
            .unwrap();

        t.join().unwrap();
        t2.join().unwrap();
    }
}
<|endoftext|>


<commit_before>use serde::Deserialize;

pub type Node = clang_ast::Node<Clang>;

#[derive(Deserialize)]
pub enum Clang {
    NamespaceDecl(NamespaceDecl),
    EnumDecl(EnumDecl),
    EnumConstantDecl(EnumConstantDecl),
    ImplicitCastExpr,
    ConstantExpr(ConstantExpr),
    Unknown,
}

#[derive(Deserialize)]
pub struct NamespaceDecl {
    pub name: Option<String>,
}

#[derive(Deserialize)]
pub struct EnumDecl {
    pub name: Option<String>,
    #[serde(rename = "fixedUnderlyingType")]
    pub fixed_underlying_type: Option<Type>,
}

#[derive(Deserialize)]
pub struct EnumConstantDecl {
    pub name: String,
}

#[derive(Deserialize)]
pub struct ConstantExpr {
    pub value: String,
}

#[derive(Deserialize)]
pub struct Type {
    #[serde(rename = "qualType")]
    pub qual_type: String,
    #[serde(rename = "desugaredQualType")]
    pub desugared_qual_type: Option<String>,
}

#[cfg(all(test, target_pointer_width = "64"))]
const _: [(); std::mem::size_of::<Node>()] = [(); 112];
<commit_msg>Adopt Box<str> for some AST size shrinking<commit_after>use serde::Deserialize;

pub type Node = clang_ast::Node<Clang>;

#[derive(Deserialize)]
pub enum Clang {
    NamespaceDecl(NamespaceDecl),
    EnumDecl(EnumDecl),
    EnumConstantDecl(EnumConstantDecl),
    ImplicitCastExpr,
    ConstantExpr(ConstantExpr),
    Unknown,
}

#[derive(Deserialize)]
pub struct NamespaceDecl {
    pub name: Option<Box<str>>,
}

#[derive(Deserialize)]
pub struct EnumDecl {
    pub name: Option<Box<str>>,
    #[serde(rename = "fixedUnderlyingType")]
    pub fixed_underlying_type: Option<Type>,
}

#[derive(Deserialize)]
pub struct EnumConstantDecl {
    pub name: Box<str>,
}

#[derive(Deserialize)]
pub struct ConstantExpr {
    pub value: Box<str>,
}

#[derive(Deserialize)]
pub struct Type {
    #[serde(rename = "qualType")]
    pub qual_type: Box<str>,
    #[serde(rename = "desugaredQualType")]
    pub desugared_qual_type: Option<Box<str>>,
}

#[cfg(all(test, target_pointer_width = "64"))]
const _: [(); std::mem::size_of::<Node>()] = [(); 88];
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::io::Cursor;
use std::ops::Deref;
use std::rc::Rc;

use digest::digest_reader;
use serde_json;
use sha2::Sha256;
use url::Url;
use url_serde;

use resman::{AudioBuffer, ResMan};
use super::routegraph::RouteGraph;
use super::adjlist::AdjList;

#[derive(Debug)]
pub enum Error {
    /// No effect matches the metadata requested.
    NoMatchingEffect(EffectId),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

/// Serializable info needed to look up an effect.
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectId {
    /// Canonical name of the effect
    name: String,
    /// Hash of the effect's definition file, or None if the effect is primitive
    sha256: Option<[u8; 32]>,
    // TODO: consider a smallset.
    // TODO: use #[serde(with = "url_serde")]
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
}

/// All information that will be loaded from disk/network to describe how to
/// synthesize the Effect.
#[derive(Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectDesc {
    meta: EffectMeta,
    adjlist: AdjList,
}

/// Validated version of `EffectDesc`. Guaranteed to be synthesizable.
#[derive(Debug)]
pub struct Effect {
    id: EffectId,
    meta: EffectMeta,
    // TODO: Effects are immutable, so we can make this an AdjList and store
    // the connectivity information separately.
    // option, because effect MAY be primitive.
    data: EffectData,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectMeta {
    /// Canonical name of the effect
    name: String,
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
    inputs: Vec<EffectInput>,
    outputs: Vec<EffectOutput>,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectIO {
    name: String,
    channel: u8,
}
pub type EffectInput = EffectIO;
pub type EffectOutput = EffectIO;

/// Implementation details of an Effect.
/// Either its route graph, a primitive effect, etc.
#[derive(Debug)]
pub enum EffectData {
    RouteGraph(RouteGraph),
    Primitive(PrimitiveEffect),
    Buffer(AudioBuffer),
}

/// Effects that cannot be decomposed; they have no implementation details and
/// must be implemented directly by the renderer.
#[derive(Debug, Copy, Clone)]
pub enum PrimitiveEffect {
    /// Primitive Delay effect
    Delay,
    /// Primitive Constant effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    F32Constant,
    /// Sum 2 floating point streams.
    Sum2,
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate A/B.
    /// Note: because not all floating point numbers have inverses,
    /// A * (1/B) != A/B. Hence, we need division (not inversion) for proper
    /// precision.
    Divide,
    /// Primitive effect to calculate A%B (true modulo; not remainder.
    /// Result, y,  is always positive: y is bounded by [0, B).
    Modulo,
    /// Primitive effect to return the sample-wise minimum of two input streams.
    /// Max(A, B) can be implemented as -Min(-A, -B).
    /// The choice to define Min instead of Max was mostly arbitrary,
    /// and chosen because Min is more common in linear programming to avoid dealing
    /// with Inf.
    Minimum,
}

impl Effect {
    pub fn are_slots_connected(&self, from_slot: u32, to_slot: u32) -> bool {
        match self.data {
            EffectData::RouteGraph(ref g) => g.are_slots_connected(from_slot, to_slot),
            // For primitive effects, we assume ALL slots are connected.
            _ => true,
        }
    }
    pub fn id(&self) -> &EffectId {
        &self.id
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Given the effect's information, and an interface by which to load
    /// resources, return an actual Effect.
    pub fn from_id(id: EffectId, resman: &ResMan) -> ResultE<Rc<Self>> {
        // For primitive effects, don't attempt to locate their descriptions (they don't exist)
        let prim_effect = id.get_primitive_url().and_then(|url| match url.path() {
            "/Delay"       => Some(PrimitiveEffect::Delay),
            "/F32Constant" => Some(PrimitiveEffect::F32Constant),
            "/Sum2"        => Some(PrimitiveEffect::Sum2),
            "/Multiply"    => Some(PrimitiveEffect::Multiply),
            "/Divide"      => Some(PrimitiveEffect::Divide),
            "/Modulo"      => Some(PrimitiveEffect::Modulo),
            "/Minimum"     => Some(PrimitiveEffect::Minimum),
            _ => {
                warn!("Unrecognized primitive effect: {} (full url: {})", url.path(), url);
                None
            }
        });
        // Attempt to instantiate a primitive effect, if the URL matched.
        if let Some(prim_effect) = prim_effect {
            if id.sha256 == None {
                let me = Self {
                    meta: EffectMeta {
                        name: id.name.clone(),
                        urls: id.urls.clone(),
                        // Primitive effects have undocumented I/O;
                        inputs: Default::default(),
                        outputs: Default::default(),
                    },
                    // sha256 was already verified; no need to update it
                    id: id,
                    data: EffectData::Primitive(prim_effect),
                };
                return Ok(Rc::new(me));
            } else {
                warn!("Attempted to load a primitive Effect, but cannot because of mismatched sha256");
            }
        }

        // Locate descriptions for non-primitive effects
        for (path, reader) in resman.find_effect(&id) {
            // Try to deserialize to an effect description
            let desc: Result<EffectDesc, serde_json::Error> = serde_json::from_reader(reader);
            match desc {
                Ok(desc) => {
                    if desc.id().name() == id.name() {
                        // TODO: since we've matched the effect, we only need to recalculate
                        // the id if the original search had missing hashes.
                        let id = desc.id();
                        match RouteGraph::from_adjlist(desc.adjlist, resman) {
                            Ok(graph) => {
                                let me = Self {
                                    id,
                                    meta: desc.meta,
                                    data: EffectData::RouteGraph(graph),
                                };
                                // TODO: implement some form of caching
                                return Ok(Rc::new(me));
                            },
                            Err(error) => warn!("RouteGraph::from_adjlist failed: {:?}", error)
                        }
                    } else {
                        trace!("[{:?}] Effect names differ: wanted {:?} got {:?}", path, id.name(), desc.id().name());
                    }
                },
                Err(error) => {
                    // Try parsing the file as an audio stream.
                    if let Ok(buffer) = AudioBuffer::from_path(path.clone()) {
                        let me = Self {
                            meta: EffectMeta {
                                name: id.name.clone(),
                                urls: id.urls.clone(),
                                // TODO: should be able to extract the number of outputs from the
                                // audio buffer
                                inputs: Default::default(),
                                outputs: Default::default(),
                            },
                            // TODO: refactor to avoid this clone.
                            // TODO: sha256 may need to be updated.
                            id: id.clone(),
                            data: EffectData::Buffer(buffer),
                        };
                        // TODO: implement some form of caching
                        return Ok(Rc::new(me));
                    } else {
                        warn!("[{:?}] Unable to deserialize EffectDesc: {:?}", path, error)
                    }
                }
            }
        }
        // No matching effects
        Err(Error::NoMatchingEffect(id))
    }
    pub fn data(&self) -> &EffectData {
        &self.data
    }
}

impl EffectId {
    pub fn new<U>(name: String, sha256: Option<[u8; 32]>, urls: U) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            sha256,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
        }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn sha256(&self) -> &Option<[u8; 32]> {
        &self.sha256
    }
    /// Returns true if the effect cannot be decomposed.
    /// This is determined by the effect providing a SINGLE url, with the primitive:// Schema
    pub fn is_primitive(&self) -> bool {
        self.urls.len() == 1 && self.urls.iter().all(|url| {
            url.scheme() == "primitive"
        })
    }
    pub fn get_primitive_url(&self) -> Option<&Url> {
        if self.is_primitive() {
            self.urls.iter().next().map(|url| url.deref())
        } else {
            None
        }
    }
}

impl EffectDesc {
    pub fn new(meta: EffectMeta, adjlist: AdjList) -> Self {
        Self{ meta, adjlist }
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    pub fn id(&self) -> EffectId {
        // TODO: calculate sha using a smaller buffer
        let as_vec = serde_json::to_vec(self).unwrap();
        let result = digest_reader::<Sha256>(&mut Cursor::new(as_vec)).unwrap();
        let mut hash: [u8; 32] = Default::default();
        hash.copy_from_slice(result.as_slice());
        EffectId {
            name: self.meta.name.clone(),
            sha256: Some(hash),
            urls: self.meta.urls.clone(),
        }
    }
    pub fn adjlist(&self) -> &AdjList {
        &self.adjlist
    }
}

impl EffectMeta {
    pub fn new<U>(name: String, urls: U, inputs: Vec<EffectInput>, outputs: Vec<EffectOutput>) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
            inputs,
            outputs,
        }
    }
    pub fn name(&self) -> &str {
        self.name.as_str()
    }
    pub fn inputs(&self) -> &Vec<EffectInput> {
        &self.inputs
    }
    pub fn outputs(&self) -> &Vec<EffectOutput> {
        &self.outputs
    }
    pub fn inputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectInput> + 'a {
        self.inputs.iter().filter(move |item| item.name() == name)
    }
    pub fn outputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectOutput> + 'a {
        self.outputs.iter().filter(move |item| item.name() == name)
    }
}

impl EffectIO {
    pub fn new(name: String, channel: u8) -> Self {
        Self{ name, channel }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn channel(&self) -> u8 {
        self.channel
    }
    pub fn is_source(&self) -> bool {
        self.name == "source"
    }
    pub fn is_result(&self) -> bool {
        self.name == "result"
    }
}

impl PartialEq for EffectMeta {
    // Equality implemented in a way where we can easily check things like
    //   "Is this the same primitive Delay effect this renderer knows how to implement?"
    fn eq(&self, other: &EffectMeta) -> bool {
        self.name == other.name &&
            self.urls == other.urls
    }
}
impl Eq for EffectMeta {}

impl PartialEq for Effect {
    fn eq(&self, other: &Effect) -> bool {
        self.meta == other.meta
    }
}
impl Eq for Effect {}

<commit_msg>Provide more context to warnings<commit_after>use std::collections::HashSet;
use std::io::Cursor;
use std::ops::Deref;
use std::rc::Rc;

use digest::digest_reader;
use serde_json;
use sha2::Sha256;
use url::Url;
use url_serde;

use resman::{AudioBuffer, ResMan};
use super::routegraph::RouteGraph;
use super::adjlist::AdjList;

#[derive(Debug)]
pub enum Error {
    /// No effect matches the metadata requested.
    NoMatchingEffect(EffectId),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

/// Serializable info needed to look up an effect.
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectId {
    /// Canonical name of the effect
    name: String,
    /// Hash of the effect's definition file, or None if the effect is primitive
    sha256: Option<[u8; 32]>,
    // TODO: consider a smallset.
    // TODO: use #[serde(with = "url_serde")]
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
}

/// All information that will be loaded from disk/network to describe how to
/// synthesize the Effect.
#[derive(Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectDesc {
    meta: EffectMeta,
    adjlist: AdjList,
}

/// Validated version of `EffectDesc`. Guaranteed to be synthesizable.
#[derive(Debug)]
pub struct Effect {
    id: EffectId,
    meta: EffectMeta,
    // TODO: Effects are immutable, so we can make this an AdjList and store
    // the connectivity information separately.
    // option, because effect MAY be primitive.
    data: EffectData,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectMeta {
    /// Canonical name of the effect
    name: String,
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
    inputs: Vec<EffectInput>,
    outputs: Vec<EffectOutput>,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectIO {
    name: String,
    channel: u8,
}
pub type EffectInput = EffectIO;
pub type EffectOutput = EffectIO;

/// Implementation details of an Effect.
/// Either its route graph, a primitive effect, etc.
#[derive(Debug)]
pub enum EffectData {
    RouteGraph(RouteGraph),
    Primitive(PrimitiveEffect),
    Buffer(AudioBuffer),
}

/// Effects that cannot be decomposed; they have no implementation details and
/// must be implemented directly by the renderer.
#[derive(Debug, Copy, Clone)]
pub enum PrimitiveEffect {
    /// Primitive Delay effect
    Delay,
    /// Primitive Constant effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    F32Constant,
    /// Sum 2 floating point streams.
    Sum2,
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate A/B.
    /// Note: because not all floating point numbers have inverses,
    /// A * (1/B) != A/B. Hence, we need division (not inversion) for proper
    /// precision.
    Divide,
    /// Primitive effect to calculate A%B (true modulo; not remainder.
    /// Result, y,  is always positive: y is bounded by [0, B).
    Modulo,
    /// Primitive effect to return the sample-wise minimum of two input streams.
    /// Max(A, B) can be implemented as -Min(-A, -B).
    /// The choice to define Min instead of Max was mostly arbitrary,
    /// and chosen because Min is more common in linear programming to avoid dealing
    /// with Inf.
    Minimum,
}

impl Effect {
    pub fn are_slots_connected(&self, from_slot: u32, to_slot: u32) -> bool {
        match self.data {
            EffectData::RouteGraph(ref g) => g.are_slots_connected(from_slot, to_slot),
            // For primitive effects, we assume ALL slots are connected.
            _ => true,
        }
    }
    pub fn id(&self) -> &EffectId {
        &self.id
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Given the effect's information, and an interface by which to load
    /// resources, return an actual Effect.
    pub fn from_id(id: EffectId, resman: &ResMan) -> ResultE<Rc<Self>> {
        // For primitive effects, don't attempt to locate their descriptions (they don't exist)
        let prim_effect = id.get_primitive_url().and_then(|url| match url.path() {
            "/Delay"       => Some(PrimitiveEffect::Delay),
            "/F32Constant" => Some(PrimitiveEffect::F32Constant),
            "/Sum2"        => Some(PrimitiveEffect::Sum2),
            "/Multiply"    => Some(PrimitiveEffect::Multiply),
            "/Divide"      => Some(PrimitiveEffect::Divide),
            "/Modulo"      => Some(PrimitiveEffect::Modulo),
            "/Minimum"     => Some(PrimitiveEffect::Minimum),
            _ => {
                warn!("Unrecognized primitive effect: {} (full url: {})", url.path(), url);
                None
            }
        });
        // Attempt to instantiate a primitive effect, if the URL matched.
        if let Some(prim_effect) = prim_effect {
            if id.sha256 == None {
                let me = Self {
                    meta: EffectMeta {
                        name: id.name.clone(),
                        urls: id.urls.clone(),
                        // Primitive effects have undocumented I/O;
                        inputs: Default::default(),
                        outputs: Default::default(),
                    },
                    // sha256 was already verified; no need to update it
                    id: id,
                    data: EffectData::Primitive(prim_effect),
                };
                return Ok(Rc::new(me));
            } else {
                warn!("Attempted to load a primitive Effect, but cannot because of mismatched sha256: {:?}", id.sha256);
            }
        }

        // Locate descriptions for non-primitive effects
        for (path, reader) in resman.find_effect(&id) {
            // Try to deserialize to an effect description
            let desc: Result<EffectDesc, serde_json::Error> = serde_json::from_reader(reader);
            match desc {
                Ok(desc) => {
                    if desc.id().name() == id.name() {
                        // TODO: since we've matched the effect, we only need to recalculate
                        // the id if the original search had missing hashes.
                        let id = desc.id();
                        match RouteGraph::from_adjlist(desc.adjlist, resman) {
                            Ok(graph) => {
                                let me = Self {
                                    id,
                                    meta: desc.meta,
                                    data: EffectData::RouteGraph(graph),
                                };
                                // TODO: implement some form of caching
                                return Ok(Rc::new(me));
                            },
                            Err(error) => warn!("[{:?}] RouteGraph::from_adjlist failed: {:?}", path, error)
                        }
                    } else {
                        trace!("[{:?}] Effect names differ: wanted {:?} got {:?}", path, id.name(), desc.id().name());
                    }
                },
                Err(error) => {
                    // Try parsing the file as an audio stream.
                    if let Ok(buffer) = AudioBuffer::from_path(path.clone()) {
                        let me = Self {
                            meta: EffectMeta {
                                name: id.name.clone(),
                                urls: id.urls.clone(),
                                // TODO: should be able to extract the number of outputs from the
                                // audio buffer
                                inputs: Default::default(),
                                outputs: Default::default(),
                            },
                            // TODO: refactor to avoid this clone.
                            // TODO: sha256 may need to be updated.
                            id: id.clone(),
                            data: EffectData::Buffer(buffer),
                        };
                        // TODO: implement some form of caching
                        return Ok(Rc::new(me));
                    } else {
                        warn!("[{:?}] Unable to deserialize EffectDesc: {:?}", path, error)
                    }
                }
            }
        }
        // No matching effects
        Err(Error::NoMatchingEffect(id))
    }
    pub fn data(&self) -> &EffectData {
        &self.data
    }
}

impl EffectId {
    pub fn new<U>(name: String, sha256: Option<[u8; 32]>, urls: U) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            sha256,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
        }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn sha256(&self) -> &Option<[u8; 32]> {
        &self.sha256
    }
    /// Returns true if the effect cannot be decomposed.
    /// This is determined by the effect providing a SINGLE url, with the primitive:// Schema
    pub fn is_primitive(&self) -> bool {
        self.urls.len() == 1 && self.urls.iter().all(|url| {
            url.scheme() == "primitive"
        })
    }
    pub fn get_primitive_url(&self) -> Option<&Url> {
        if self.is_primitive() {
            self.urls.iter().next().map(|url| url.deref())
        } else {
            None
        }
    }
}

impl EffectDesc {
    pub fn new(meta: EffectMeta, adjlist: AdjList) -> Self {
        Self{ meta, adjlist }
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    pub fn id(&self) -> EffectId {
        // TODO: calculate sha using a smaller buffer
        let as_vec = serde_json::to_vec(self).unwrap();
        let result = digest_reader::<Sha256>(&mut Cursor::new(as_vec)).unwrap();
        let mut hash: [u8; 32] = Default::default();
        hash.copy_from_slice(result.as_slice());
        EffectId {
            name: self.meta.name.clone(),
            sha256: Some(hash),
            urls: self.meta.urls.clone(),
        }
    }
    pub fn adjlist(&self) -> &AdjList {
        &self.adjlist
    }
}

impl EffectMeta {
    pub fn new<U>(name: String, urls: U, inputs: Vec<EffectInput>, outputs: Vec<EffectOutput>) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            urls: urls.into_iter().map(url_serde::Serde).collect(),
            inputs,
            outputs,
        }
    }
    pub fn name(&self) -> &str {
        self.name.as_str()
    }
    pub fn inputs(&self) -> &Vec<EffectInput> {
        &self.inputs
    }
    pub fn outputs(&self) -> &Vec<EffectOutput> {
        &self.outputs
    }
    pub fn inputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectInput> + 'a {
        self.inputs.iter().filter(move |item| item.name() == name)
    }
    pub fn outputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectOutput> + 'a {
        self.outputs.iter().filter(move |item| item.name() == name)
    }
}

impl EffectIO {
    pub fn new(name: String, channel: u8) -> Self {
        Self{ name, channel }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn channel(&self) -> u8 {
        self.channel
    }
    pub fn is_source(&self) -> bool {
        self.name == "source"
    }
    pub fn is_result(&self) -> bool {
        self.name == "result"
    }
}

impl PartialEq for EffectMeta {
    // Equality implemented in a way where we can easily check things like
    //   "Is this the same primitive Delay effect this renderer knows how to implement?"
    fn eq(&self, other: &EffectMeta) -> bool {
        self.name == other.name &&
            self.urls == other.urls
    }
}
impl Eq for EffectMeta {}

impl PartialEq for Effect {
    fn eq(&self, other: &Effect) -> bool {
        self.meta == other.meta
    }
}
impl Eq for Effect {}

<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::io::Cursor;
use std::ops::Deref;
use std::rc::Rc;

use digest::digest_reader;
use serde_json;
use sha2::Sha256;
use url::Url;
use url_serde;

use resman::{AudioBuffer, ResMan};
use super::routegraph::RouteGraph;
use super::adjlist::AdjList;

#[derive(Debug)]
pub enum Error {
    /// No effect matches the metadata requested.
    NoMatchingEffect(EffectId),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

/// Serializable info needed to look up an effect.
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectId {
    /// Canonical name of the effect
    name: String,
    /// Hash of the effect's definition file, or None if the effect is primitive
    sha256: Option<[u8; 32]>,
    // TODO: consider a smallset.
    // TODO: use #[serde(with = "url_serde")]
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
}

/// All information that will be loaded from disk/network to describe how to
/// synthesize the Effect.
#[derive(Serialize, Deserialize)]
pub struct EffectDesc {
    meta: EffectMeta,
    adjlist: AdjList,
}

/// Validated version of EffectDesc. Guaranteed to be synthesizable.
pub struct Effect {
    id: EffectId,
    meta: EffectMeta,
    // TODO: Effects are immutable, so we can make this an AdjList and store
    // the connectivity information separately.
    // option, because effect MAY be primitive.
    data: EffectData,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectMeta {
    /// Canonical name of the effect
    name: String,
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
    inputs: Vec<EffectInput>,
    outputs: Vec<EffectOutput>,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectIO {
    name: String,
    channel: u8,
}
pub type EffectInput = EffectIO;
pub type EffectOutput = EffectIO;

/// Implementation details of an Effect.
/// Either its route graph, a primitive effect, etc.
pub enum EffectData {
    RouteGraph(RouteGraph),
    Primitive(PrimitiveEffect),
    Buffer(AudioBuffer),
}

/// Effects that cannot be decomposed; they have no implementation details and
/// must be implemented directly by the renderer.
#[derive(Debug, Copy, Clone)]
pub enum PrimitiveEffect {
    /// Primitive Delay effect
    Delay,
    /// Primitive Constant effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    F32Constant,
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate A/B.
    /// Note: because not all floating point numbers have inverses,
    /// A * (1/B) != A/B. Hence, we need division (not inversion) for proper
    /// precision.
    Divide,
    /// Primitive effect to calculate A%B (true modulo; not remainder.
    /// Result, y,  is always positive: y is bounded by [0, B).
    Modulo,
    /// Primitive effect to return the sample-wise minimum of two input streams.
    /// Max(A, B) can be implemented as -Min(-A, -B).
    /// The choice to define Min instead of Max was mostly arbitrary,
    /// and chosen because Min is more common in linear programming to avoid dealing
    /// with Inf.
    Minimum,
}

impl Effect {
    pub fn are_slots_connected(&self, from_slot: u32, to_slot: u32) -> bool {
        match self.data {
            EffectData::RouteGraph(ref g) => g.are_slots_connected(from_slot, to_slot),
            // For primitive effects, we assume ALL slots are connected.
            _ => true,
        }
    }
    pub fn id(&self) -> EffectId {
        EffectId {
            name: self.meta.name.clone(),
            sha256: None,
            urls: self.meta.urls.clone(),
        }
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Given the effect's information, and an interface by which to load
    /// resources, return an actual Effect.
    pub fn from_id(id: EffectId, resman: &ResMan) -> ResultE<Rc<Self>> {
        // For primitive effects, don't attempt to locate their descriptions (they don't exist)
        let prim_effect = id.get_primitive_url().map(|url| match url.path() {
            "/F32Constant" => PrimitiveEffect::F32Constant,
            "/Delay" => PrimitiveEffect::Delay,
            "/Multiply" => PrimitiveEffect::Multiply,
            "/Divide" => PrimitiveEffect::Divide,
            "/Modulo" => PrimitiveEffect::Modulo,
            "/Minimum" => PrimitiveEffect::Minimum,
            _ => panic!("Unrecognized primitive effect: {} (full url: {})", url.path(), url),
        });
        if let Some(prim_effect) = prim_effect {
            let me = Self {
                meta: EffectMeta {
                    name: id.name.clone(),
                    urls: id.urls.clone(),
                    // Primitive effects have undocumented I/O;
                    inputs: Default::default(),
                    outputs: Default::default(),
                },
                id: id,
                data: EffectData::Primitive(prim_effect),
            };
            return Ok(Rc::new(me));
        }

        // Locate descriptions for non-primitive effects
        for (path, reader) in resman.find_effect(&id) {
            // Try to deserialize to an effect description
            let desc: Result<EffectDesc, serde_json::Error> = serde_json::from_reader(reader);
            match desc {
                Ok(desc) => {
                    // TODO: since we've matched the effect, we only need to recalculate
                    // the id if the original search had missing hashes.
                    let id = desc.id();
                    match RouteGraph::from_adjlist(desc.adjlist, resman) {
                        Ok(graph) => {
                            let me = Self {
                                id,
                                meta: desc.meta,
                                data: EffectData::RouteGraph(graph),
                            };
                            // TODO: implement some form of caching
                            return Ok(Rc::new(me));
                        },
                        Err(error) => println!("Warning: RouteGraph::from_adjlist failed: {:?}", error)
                    }
                },
                Err(error) => {
                    // Try parsing the file as an audio stream.
                    if let Ok(buffer) = AudioBuffer::from_path(path) {
                        let me = Self {
                            meta: EffectMeta {
                                name: id.name.clone(),
                                urls: id.urls.clone(),
                                // TODO: should be able to extract the number of outputs from the
                                // audio buffer
                                inputs: Default::default(),
                                outputs: Default::default(),
                            },
                            // TODO: refactor to avoid this clone.
                            id: id.clone(),
                            data: EffectData::Buffer(buffer),
                        };
                        // TODO: implement some form of caching
                        return Ok(Rc::new(me));
                    } else {
                        println!("Warning: unable to deserialize EffectDesc: {:?}", error)
                    }
                }
            }
        }
        // No matching effects
        Err(Error::NoMatchingEffect(id))
    }
    pub fn data(&self) -> &EffectData {
        &self.data
    }
}

impl EffectId {
    pub fn new<U>(name: String, sha256: Option<[u8; 32]>, urls: U) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            sha256,
            urls: urls.into_iter().map(|url| url_serde::Serde(url)).collect(),
        }
    }
    pub fn sha256(&self) -> &Option<[u8; 32]> {
        &self.sha256
    }
    /// Returns true if the effect cannot be decomposed.
    /// This is determined by the effect providing a SINGLE url, with the primitive:// Schema
    pub fn is_primitive(&self) -> bool {
        self.urls.len() == 1 && self.urls.iter().all(|url| {
            url.scheme() == "primitive"
        })
    }
    pub fn get_primitive_url(&self) -> Option<&Url> {
        if self.is_primitive() {
            self.urls.iter().next().map(|url| url.deref())
        } else {
            None
        }
    }
}

impl EffectDesc {
    pub fn new(meta: EffectMeta, adjlist: AdjList) -> Self {
        Self{ meta, adjlist }
    }
    pub fn id(&self) -> EffectId {
        // TODO: calculate sha using a smaller buffer
        let as_vec = serde_json::to_vec(self).unwrap();
        let result = digest_reader::<Sha256>(&mut Cursor::new(as_vec)).unwrap();
        let mut hash: [u8; 32] = Default::default();
        hash.copy_from_slice(result.as_slice());
        EffectId {
            name: self.meta.name.clone(),
            sha256: Some(hash),
            urls: self.meta.urls.clone(),
        }
    }
}

impl EffectMeta {
    pub fn new<U>(name: String, urls: U, inputs: Vec<EffectInput>, outputs: Vec<EffectOutput>) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            urls: urls.into_iter().map(|url| url_serde::Serde(url)).collect(),
            inputs,
            outputs,
        }
    }
    pub fn inputs(&self) -> &Vec<EffectInput> {
        &self.inputs
    }
    pub fn outputs(&self) -> &Vec<EffectOutput> {
        &self.outputs
    }
    pub fn inputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectInput> + 'a {
        self.inputs.iter().filter(move |item| item.name() == name)
    }
    pub fn outputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectOutput> + 'a {
        self.outputs.iter().filter(move |item| item.name() == name)
    }
}

impl EffectIO {
    pub fn new(name: String, channel: u8) -> Self {
        Self{ name, channel }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn channel(&self) -> u8 {
        self.channel
    }
}

impl PartialEq for EffectMeta {
    // Equality implemented in a way where we can easily check things like
    //   "Is this the same primitive Delay effect this renderer knows how to implement?"
    fn eq(&self, other: &EffectMeta) -> bool {
        self.name == other.name &&
            self.urls == other.urls
    }
}
impl Eq for EffectMeta {}

impl PartialEq for Effect {
    fn eq(&self, other: &Effect) -> bool {
        self.meta == other.meta
    }
}
impl Eq for Effect {}

<commit_msg>More EffectIO convenience methods<commit_after>use std::collections::HashSet;
use std::io::Cursor;
use std::ops::Deref;
use std::rc::Rc;

use digest::digest_reader;
use serde_json;
use sha2::Sha256;
use url::Url;
use url_serde;

use resman::{AudioBuffer, ResMan};
use super::routegraph::RouteGraph;
use super::adjlist::AdjList;

#[derive(Debug)]
pub enum Error {
    /// No effect matches the metadata requested.
    NoMatchingEffect(EffectId),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

/// Serializable info needed to look up an effect.
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectId {
    /// Canonical name of the effect
    name: String,
    /// Hash of the effect's definition file, or None if the effect is primitive
    sha256: Option<[u8; 32]>,
    // TODO: consider a smallset.
    // TODO: use #[serde(with = "url_serde")]
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
}

/// All information that will be loaded from disk/network to describe how to
/// synthesize the Effect.
#[derive(Serialize, Deserialize)]
pub struct EffectDesc {
    meta: EffectMeta,
    adjlist: AdjList,
}

/// Validated version of EffectDesc. Guaranteed to be synthesizable.
pub struct Effect {
    id: EffectId,
    meta: EffectMeta,
    // TODO: Effects are immutable, so we can make this an AdjList and store
    // the connectivity information separately.
    // option, because effect MAY be primitive.
    data: EffectData,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectMeta {
    /// Canonical name of the effect
    name: String,
    /// List of URLs where the Effect can be obtained
    urls: HashSet<url_serde::Serde<Url>>,
    inputs: Vec<EffectInput>,
    outputs: Vec<EffectOutput>,
}

#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
pub struct EffectIO {
    name: String,
    channel: u8,
}
pub type EffectInput = EffectIO;
pub type EffectOutput = EffectIO;

/// Implementation details of an Effect.
/// Either its route graph, a primitive effect, etc.
pub enum EffectData {
    RouteGraph(RouteGraph),
    Primitive(PrimitiveEffect),
    Buffer(AudioBuffer),
}

/// Effects that cannot be decomposed; they have no implementation details and
/// must be implemented directly by the renderer.
#[derive(Debug, Copy, Clone)]
pub enum PrimitiveEffect {
    /// Primitive Delay effect
    Delay,
    /// Primitive Constant effect.
    /// Also serves as a unit step;
    /// Returns the float value for t >= 0, else 0.
    F32Constant,
    /// Primitive effect to multiply TWO input streams sample-wise.
    Multiply,
    /// Primitive effect to calculate A/B.
    /// Note: because not all floating point numbers have inverses,
    /// A * (1/B) != A/B. Hence, we need division (not inversion) for proper
    /// precision.
    Divide,
    /// Primitive effect to calculate A%B (true modulo; not remainder.
    /// Result, y,  is always positive: y is bounded by [0, B).
    Modulo,
    /// Primitive effect to return the sample-wise minimum of two input streams.
    /// Max(A, B) can be implemented as -Min(-A, -B).
    /// The choice to define Min instead of Max was mostly arbitrary,
    /// and chosen because Min is more common in linear programming to avoid dealing
    /// with Inf.
    Minimum,
}

impl Effect {
    pub fn are_slots_connected(&self, from_slot: u32, to_slot: u32) -> bool {
        match self.data {
            EffectData::RouteGraph(ref g) => g.are_slots_connected(from_slot, to_slot),
            // For primitive effects, we assume ALL slots are connected.
            _ => true,
        }
    }
    pub fn id(&self) -> EffectId {
        EffectId {
            name: self.meta.name.clone(),
            sha256: None,
            urls: self.meta.urls.clone(),
        }
    }
    pub fn meta(&self) -> &EffectMeta {
        &self.meta
    }
    /// Given the effect's information, and an interface by which to load
    /// resources, return an actual Effect.
    pub fn from_id(id: EffectId, resman: &ResMan) -> ResultE<Rc<Self>> {
        // For primitive effects, don't attempt to locate their descriptions (they don't exist)
        let prim_effect = id.get_primitive_url().map(|url| match url.path() {
            "/F32Constant" => PrimitiveEffect::F32Constant,
            "/Delay" => PrimitiveEffect::Delay,
            "/Multiply" => PrimitiveEffect::Multiply,
            "/Divide" => PrimitiveEffect::Divide,
            "/Modulo" => PrimitiveEffect::Modulo,
            "/Minimum" => PrimitiveEffect::Minimum,
            _ => panic!("Unrecognized primitive effect: {} (full url: {})", url.path(), url),
        });
        if let Some(prim_effect) = prim_effect {
            let me = Self {
                meta: EffectMeta {
                    name: id.name.clone(),
                    urls: id.urls.clone(),
                    // Primitive effects have undocumented I/O;
                    inputs: Default::default(),
                    outputs: Default::default(),
                },
                id: id,
                data: EffectData::Primitive(prim_effect),
            };
            return Ok(Rc::new(me));
        }

        // Locate descriptions for non-primitive effects
        for (path, reader) in resman.find_effect(&id) {
            // Try to deserialize to an effect description
            let desc: Result<EffectDesc, serde_json::Error> = serde_json::from_reader(reader);
            match desc {
                Ok(desc) => {
                    // TODO: since we've matched the effect, we only need to recalculate
                    // the id if the original search had missing hashes.
                    let id = desc.id();
                    match RouteGraph::from_adjlist(desc.adjlist, resman) {
                        Ok(graph) => {
                            let me = Self {
                                id,
                                meta: desc.meta,
                                data: EffectData::RouteGraph(graph),
                            };
                            // TODO: implement some form of caching
                            return Ok(Rc::new(me));
                        },
                        Err(error) => println!("Warning: RouteGraph::from_adjlist failed: {:?}", error)
                    }
                },
                Err(error) => {
                    // Try parsing the file as an audio stream.
                    if let Ok(buffer) = AudioBuffer::from_path(path) {
                        let me = Self {
                            meta: EffectMeta {
                                name: id.name.clone(),
                                urls: id.urls.clone(),
                                // TODO: should be able to extract the number of outputs from the
                                // audio buffer
                                inputs: Default::default(),
                                outputs: Default::default(),
                            },
                            // TODO: refactor to avoid this clone.
                            id: id.clone(),
                            data: EffectData::Buffer(buffer),
                        };
                        // TODO: implement some form of caching
                        return Ok(Rc::new(me));
                    } else {
                        println!("Warning: unable to deserialize EffectDesc: {:?}", error)
                    }
                }
            }
        }
        // No matching effects
        Err(Error::NoMatchingEffect(id))
    }
    pub fn data(&self) -> &EffectData {
        &self.data
    }
}

impl EffectId {
    pub fn new<U>(name: String, sha256: Option<[u8; 32]>, urls: U) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            sha256,
            urls: urls.into_iter().map(|url| url_serde::Serde(url)).collect(),
        }
    }
    pub fn sha256(&self) -> &Option<[u8; 32]> {
        &self.sha256
    }
    /// Returns true if the effect cannot be decomposed.
    /// This is determined by the effect providing a SINGLE url, with the primitive:// Schema
    pub fn is_primitive(&self) -> bool {
        self.urls.len() == 1 && self.urls.iter().all(|url| {
            url.scheme() == "primitive"
        })
    }
    pub fn get_primitive_url(&self) -> Option<&Url> {
        if self.is_primitive() {
            self.urls.iter().next().map(|url| url.deref())
        } else {
            None
        }
    }
}

impl EffectDesc {
    pub fn new(meta: EffectMeta, adjlist: AdjList) -> Self {
        Self{ meta, adjlist }
    }
    pub fn id(&self) -> EffectId {
        // TODO: calculate sha using a smaller buffer
        let as_vec = serde_json::to_vec(self).unwrap();
        let result = digest_reader::<Sha256>(&mut Cursor::new(as_vec)).unwrap();
        let mut hash: [u8; 32] = Default::default();
        hash.copy_from_slice(result.as_slice());
        EffectId {
            name: self.meta.name.clone(),
            sha256: Some(hash),
            urls: self.meta.urls.clone(),
        }
    }
}

impl EffectMeta {
    pub fn new<U>(name: String, urls: U, inputs: Vec<EffectInput>, outputs: Vec<EffectOutput>) -> Self
        where U: IntoIterator<Item=Url>
    {
        Self {
            name,
            urls: urls.into_iter().map(|url| url_serde::Serde(url)).collect(),
            inputs,
            outputs,
        }
    }
    pub fn inputs(&self) -> &Vec<EffectInput> {
        &self.inputs
    }
    pub fn outputs(&self) -> &Vec<EffectOutput> {
        &self.outputs
    }
    pub fn inputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectInput> + 'a {
        self.inputs.iter().filter(move |item| item.name() == name)
    }
    pub fn outputs_by_name<'a>(&'a self, name: &'a str) -> impl Iterator<Item=&EffectOutput> + 'a {
        self.outputs.iter().filter(move |item| item.name() == name)
    }
}

impl EffectIO {
    pub fn new(name: String, channel: u8) -> Self {
        Self{ name, channel }
    }
    pub fn name(&self) -> &str {
        &self.name
    }
    pub fn channel(&self) -> u8 {
        self.channel
    }
    pub fn is_source(&self) -> bool {
        self.name == "source"
    }
    pub fn is_result(&self) -> bool {
        self.name == "result"
    }
}

impl PartialEq for EffectMeta {
    // Equality implemented in a way where we can easily check things like
    //   "Is this the same primitive Delay effect this renderer knows how to implement?"
    fn eq(&self, other: &EffectMeta) -> bool {
        self.name == other.name &&
            self.urls == other.urls
    }
}
impl Eq for EffectMeta {}

impl PartialEq for Effect {
    fn eq(&self, other: &Effect) -> bool {
        self.meta == other.meta
    }
}
impl Eq for Effect {}

<|endoftext|>


<commit_before>//! An implementation of a first fit allocator.
//!
//! The allocator uses a list of free blocks that can be allocated. When an
//! allocation is performed and the block is bigger than the requested size,
//! the block is splitted in 2 blocks: one used to fulfill the allocation, the
//! other is free.
//!
//! When a block is deallocated, the allocator tries to merge it with adjacent
//! blocks. The header of a block contains the necessary information to
//! retrieve the previous and next block if they exist. In order to access the
//! previous block, each block contains a footer that indicates the offset to
//! get the header.
<commit_msg>heap: Add useful types for First Fit algorithm<commit_after>//! An implementation of a first fit allocator.
//!
//! The allocator uses a list of free blocks that can be allocated. When an
//! allocation is performed and the block is bigger than the requested size,
//! the block is splitted in 2 blocks: one used to fulfill the allocation, the
//! other is free.
//!
//! When a block is deallocated, the allocator tries to merge it with adjacent
//! blocks. The header of a block contains the necessary information to
//! retrieve the previous and next block if they exist. In order to access the
//! previous block, each block contains a footer that indicates the offset to
//! get the header.

use core::ptr;
use core::mem;

use super::types::Node;

const PREVIOUS_BIT: usize = 1;
const NEXT_BIT: usize = 2;
const SIZE_MASK: usize = PREVIOUS_BIT | NEXT_BIT;

/// The header is a meta data that is found before every block. It is use to
/// know if the block is available and its size. It also indicates if the
/// current block has a predecessor and a successor.
struct Header {
    size: usize,
    free: bool,
}

impl Header {
    pub fn new(size: usize, free: bool) -> Self {
        Header {
            size: size & !SIZE_MASK,
            free: free,
        }
    }

    #[inline]
    pub fn size(&self) -> usize {
        self.size & !SIZE_MASK
    }

    pub fn has_next(&self) -> bool {
        (self.size & NEXT_BIT) == NEXT_BIT
    }

    pub fn has_prev(&self) -> bool {
        (self.size & PREVIOUS_BIT) == PREVIOUS_BIT
    }

    pub fn set_next(&mut self) {
        self.size |= NEXT_BIT;
    }

    pub fn set_prev(&mut self) {
        self.size |= PREVIOUS_BIT;
    }

    pub unsafe fn get_next(&mut self) -> *mut Header {
        if !self.has_next() {
            return ptr::null_mut();
        }

        // A block is composed of a header, the data and a footer. If there is
        // a "next" block, it is going to be right after the footer of the
        // current block
        let mut ptr = self as *mut Self as *mut u8;

        ptr = ptr.offset(mem::size_of::<Header>() as isize);
        ptr = ptr.offset((self.size & !SIZE_MASK) as isize);
        ptr = ptr.offset(mem::size_of::<Footer>() as isize);

        ptr as *mut Header
    }

    pub unsafe fn get_prev(&mut self) -> *mut Header {
        if !self.has_prev() {
            return ptr::null_mut();
        }

        let mut ptr = self as *mut Self as *mut u8;

        ptr = ptr.offset(-(mem::size_of::<Footer>() as isize));

        let footer = ptr as *const Footer;

        ptr.offset(-((*footer).header_off as isize)) as *mut Header
    }
}

/// The footer is a meta data located after the block that helps the next block
/// to find the header of the current block.
struct Footer {
    header_off: usize,
}

/// A free block is linked with other free block. The extra space used does not
/// matter because the block is free.
type FreeBlock = Node<Header>;
<|endoftext|>


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

#![forbid(unsafe_code)]
use std::{cmp::min, env};

use crate::{
    cluster::Cluster,
    experiments::{
        CompatiblityTestParams, CpuFlamegraphParams, Experiment, ExperimentParam,
        PerformanceBenchmarkParams, PerformanceBenchmarkThreeRegionSimulationParams,
        RebootRandomValidatorsParams, RecoveryTimeParams, TwinValidatorsParams,
    },
};
use anyhow::{format_err, Result};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        if env::var("RECOVERY_EXP").is_ok() {
            experiments.push(Box::new(
                RecoveryTimeParams {
                    num_accounts_to_mint: 100_000,
                }
                .build(cluster),
            ));
        }
        let count = min(3, cluster.validator_instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..10 {
            let b = Box::new(RebootRandomValidatorsParams::new(count, 0).build(cluster));
            experiments.push(b);
        }
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10)
                .enable_db_backup()
                .build(cluster),
        ));
        if env::var("TWIN_EXPERIMENT").is_ok() {
            experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        }

        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_twin_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_perf_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_compat_suite(cluster: &Cluster) -> Result<Self> {
        let count: usize = match env::var("BATCH_SIZE") {
            Ok(val) => val
                .parse()
                .map_err(|e| format_err!("Failed to parse BATCH_SIZE {}: {}", val, e))?,
            Err(_) => cluster.validator_instances().len() / 2,
        };
        let updated_image_tag = env::var("UPDATE_TO_TAG")
            .map_err(|_| format_err!("Expected environment variable UPDATE_TO_TAG"))?;
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            CompatiblityTestParams {
                count,
                updated_image_tag,
            }
            .build(cluster),
        ));
        experiments.extend(Self::new_land_blocking_suite(cluster).experiments);
        Ok(Self { experiments })
    }

    pub fn new_by_name(cluster: &Cluster, name: &str) -> Result<Self> {
        match name {
            "perf" => Ok(Self::new_perf_suite(cluster)),
            "pre_release" => Ok(Self::new_pre_release(cluster)),
            "twin" => Ok(Self::new_twin_suite(cluster)),
            "land_blocking" => Ok(Self::new_land_blocking_suite(cluster)),
            "land_blocking_compat" => Self::new_land_blocking_compat_suite(cluster),
            other => Err(format_err!("Unknown suite: {}", other)),
        }
    }
}
<commit_msg>[cluster-test] enable twin test<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]
use std::{cmp::min, env};

use crate::{
    cluster::Cluster,
    experiments::{
        CompatiblityTestParams, CpuFlamegraphParams, Experiment, ExperimentParam,
        PerformanceBenchmarkParams, PerformanceBenchmarkThreeRegionSimulationParams,
        RebootRandomValidatorsParams, RecoveryTimeParams, TwinValidatorsParams,
    },
};
use anyhow::{format_err, Result};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        if env::var("RECOVERY_EXP").is_ok() {
            experiments.push(Box::new(
                RecoveryTimeParams {
                    num_accounts_to_mint: 100_000,
                }
                .build(cluster),
            ));
        }
        let count = min(3, cluster.validator_instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..10 {
            let b = Box::new(RebootRandomValidatorsParams::new(count, 0).build(cluster));
            experiments.push(b);
        }
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10)
                .enable_db_backup()
                .build(cluster),
        ));
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_twin_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(TwinValidatorsParams { pair: 1 }.build(cluster)));
        experiments.push(Box::new(
            CpuFlamegraphParams { duration_secs: 60 }.build(cluster),
        ));
        Self { experiments }
    }

    fn new_perf_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(10).build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkThreeRegionSimulationParams {}.build(cluster),
        ));
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_fixed_tps(0, 10).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_suite(cluster: &Cluster) -> Self {
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            PerformanceBenchmarkParams::new_nodes_down(0).build(cluster),
        ));
        Self { experiments }
    }

    fn new_land_blocking_compat_suite(cluster: &Cluster) -> Result<Self> {
        let count: usize = match env::var("BATCH_SIZE") {
            Ok(val) => val
                .parse()
                .map_err(|e| format_err!("Failed to parse BATCH_SIZE {}: {}", val, e))?,
            Err(_) => cluster.validator_instances().len() / 2,
        };
        let updated_image_tag = env::var("UPDATE_TO_TAG")
            .map_err(|_| format_err!("Expected environment variable UPDATE_TO_TAG"))?;
        let mut experiments: Vec<Box<dyn Experiment>> = vec![];
        experiments.push(Box::new(
            CompatiblityTestParams {
                count,
                updated_image_tag,
            }
            .build(cluster),
        ));
        experiments.extend(Self::new_land_blocking_suite(cluster).experiments);
        Ok(Self { experiments })
    }

    pub fn new_by_name(cluster: &Cluster, name: &str) -> Result<Self> {
        match name {
            "perf" => Ok(Self::new_perf_suite(cluster)),
            "pre_release" => Ok(Self::new_pre_release(cluster)),
            "twin" => Ok(Self::new_twin_suite(cluster)),
            "land_blocking" => Ok(Self::new_land_blocking_suite(cluster)),
            "land_blocking_compat" => Self::new_land_blocking_compat_suite(cluster),
            other => Err(format_err!("Unknown suite: {}", other)),
        }
    }
}
<|endoftext|>


<commit_before>/* 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 http://mozilla.org/MPL/2.0/. */

use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::document::Document;
use dom::element::Element;
use dom::htmlelement::HTMLElement;
use dom::node::{Node, document_from_node};
use dom::virtualmethods::VirtualMethods;
use std::ascii::AsciiExt;
use std::sync::Arc;
use string_cache::Atom;
use style::servo::Stylesheet;
use style::stylesheets::{CSSRule, Origin};
use style::viewport::ViewportRule;
use util::str::{DOMString, HTML_SPACE_CHARACTERS};

#[dom_struct]
pub struct HTMLMetaElement {
    htmlelement: HTMLElement,
    stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
}

impl HTMLMetaElement {
    fn new_inherited(localName: Atom,
                     prefix: Option<DOMString>,
                     document: &Document) -> HTMLMetaElement {
        HTMLMetaElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document),
            stylesheet: DOMRefCell::new(None),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: Atom,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLMetaElement> {
        let element = HTMLMetaElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLMetaElementBinding::Wrap)
    }

    pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
        self.stylesheet.borrow().clone()
    }

    fn process_attributes(&self) {
        let element = self.upcast::<Element>();
        if let Some(name) = element.get_attribute(&ns!(), &atom!("name")).r() {
            let name = name.value().to_ascii_lowercase();
            let name = name.trim_matches(HTML_SPACE_CHARACTERS);

            if name == "viewport" {
                self.apply_viewport();
            }
        }
    }

    fn apply_viewport(&self) {
        if !::util::prefs::get_pref("layout.viewport.enabled").as_boolean().unwrap_or(false) {
            return;
        }
        let element = self.upcast::<Element>();
        if let Some(content) = element.get_attribute(&ns!(), &atom!("content")).r() {
            let content = content.value();
            if !content.is_empty() {
                if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
                    *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
                        rules: vec![CSSRule::Viewport(translated_rule)],
                        origin: Origin::Author,
                        media: None,
                        // Viewport constraints are always recomputed on resize; they don't need to
                        // force all styles to be recomputed.
                        dirty_on_viewport_size_change: false,
                    }));
                    let doc = document_from_node(self);
                    doc.invalidate_stylesheets();
                }
            }
        }
    }
}

impl HTMLMetaElementMethods for HTMLMetaElement {
    // https://html.spec.whatwg.org/multipage/#dom-meta-name
    make_getter!(Name, "name");

    // https://html.spec.whatwg.org/multipage/#dom-meta-name
    make_setter!(SetName, "name");

    // https://html.spec.whatwg.org/multipage/#dom-meta-content
    make_getter!(Content, "content");

    // https://html.spec.whatwg.org/multipage/#dom-meta-content
    make_setter!(SetContent, "content");
}

impl VirtualMethods for HTMLMetaElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        if tree_in_doc {
            self.process_attributes();
        }
    }
}
<commit_msg>Auto merge of #11257 - josephpd3:11247, r=KiChjang<commit_after>/* 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 http://mozilla.org/MPL/2.0/. */

use dom::attr::AttrValue;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding;
use dom::bindings::codegen::Bindings::HTMLMetaElementBinding::HTMLMetaElementMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{Root, RootedReference};
use dom::document::Document;
use dom::element::Element;
use dom::htmlelement::HTMLElement;
use dom::node::{Node, document_from_node};
use dom::virtualmethods::VirtualMethods;
use std::ascii::AsciiExt;
use std::sync::Arc;
use string_cache::Atom;
use style::servo::Stylesheet;
use style::stylesheets::{CSSRule, Origin};
use style::viewport::ViewportRule;
use util::str::{DOMString, HTML_SPACE_CHARACTERS};

#[dom_struct]
pub struct HTMLMetaElement {
    htmlelement: HTMLElement,
    stylesheet: DOMRefCell<Option<Arc<Stylesheet>>>,
}

impl HTMLMetaElement {
    fn new_inherited(localName: Atom,
                     prefix: Option<DOMString>,
                     document: &Document) -> HTMLMetaElement {
        HTMLMetaElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document),
            stylesheet: DOMRefCell::new(None),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: Atom,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLMetaElement> {
        let element = HTMLMetaElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLMetaElementBinding::Wrap)
    }

    pub fn get_stylesheet(&self) -> Option<Arc<Stylesheet>> {
        self.stylesheet.borrow().clone()
    }

    fn process_attributes(&self) {
        let element = self.upcast::<Element>();
        if let Some(name) = element.get_attribute(&ns!(), &atom!("name")).r() {
            let name = name.value().to_ascii_lowercase();
            let name = name.trim_matches(HTML_SPACE_CHARACTERS);

            if name == "viewport" {
                self.apply_viewport();
            }
        }
    }

    fn apply_viewport(&self) {
        if !::util::prefs::get_pref("layout.viewport.enabled").as_boolean().unwrap_or(false) {
            return;
        }
        let element = self.upcast::<Element>();
        if let Some(content) = element.get_attribute(&ns!(), &atom!("content")).r() {
            let content = content.value();
            if !content.is_empty() {
                if let Some(translated_rule) = ViewportRule::from_meta(&**content) {
                    *self.stylesheet.borrow_mut() = Some(Arc::new(Stylesheet {
                        rules: vec![CSSRule::Viewport(translated_rule)],
                        origin: Origin::Author,
                        media: None,
                        // Viewport constraints are always recomputed on resize; they don't need to
                        // force all styles to be recomputed.
                        dirty_on_viewport_size_change: false,
                    }));
                    let doc = document_from_node(self);
                    doc.invalidate_stylesheets();
                }
            }
        }
    }
}

impl HTMLMetaElementMethods for HTMLMetaElement {
    // https://html.spec.whatwg.org/multipage/#dom-meta-name
    make_getter!(Name, "name");

    // https://html.spec.whatwg.org/multipage/#dom-meta-name
    make_atomic_setter!(SetName, "name");

    // https://html.spec.whatwg.org/multipage/#dom-meta-content
    make_getter!(Content, "content");

    // https://html.spec.whatwg.org/multipage/#dom-meta-content
    make_setter!(SetContent, "content");
}

impl VirtualMethods for HTMLMetaElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        if tree_in_doc {
            self.process_attributes();
        }
    }

    fn parse_plain_attribute(&self, name: &Atom, value: DOMString) -> AttrValue {
        match name {
            &atom!("name") => AttrValue::from_atomic(value),
            _ => self.super_type().unwrap().parse_plain_attribute(name, value),
        }
    }
}
<|endoftext|>