1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Marshal container params into raw bytes

use crate::params;
use crate::params::message;
use crate::signature;
use crate::wire::marshal::base::*;
use crate::wire::marshal::MarshalContext;
use crate::wire::util::*;

pub fn marshal_param(p: &params::Param, ctx: &mut MarshalContext) -> message::Result<()> {
    match p {
        params::Param::Base(b) => marshal_base_param(&b, ctx),
        params::Param::Container(c) => marshal_container_param(&c, ctx),
    }
}

fn marshal_array(
    array: &[params::Param],
    sig: &signature::Type,
    ctx: &mut MarshalContext,
) -> message::Result<()> {
    ctx.align_to(4);
    let len_pos = ctx.buf.len();
    ctx.buf.push(0);
    ctx.buf.push(0);
    ctx.buf.push(0);
    ctx.buf.push(0);

    // we need to pad here because the padding between length and first element does not count
    // into the length
    ctx.align_to(sig.get_alignment());
    let content_pos = ctx.buf.len();
    for p in array {
        marshal_param(&p, ctx)?;
    }
    let len = ctx.buf.len() - content_pos;
    insert_u32(
        ctx.byteorder,
        len as u32,
        &mut ctx.buf[len_pos..len_pos + 4],
    );
    Ok(())
}

fn marshal_struct(params: &[params::Param], ctx: &mut MarshalContext) -> message::Result<()> {
    ctx.align_to(8);
    for p in params {
        marshal_param(&p, ctx)?;
    }
    Ok(())
}

fn marshal_variant(var: &params::Variant, ctx: &mut MarshalContext) -> message::Result<()> {
    let mut sig_str = String::new();
    var.sig.to_str(&mut sig_str);
    marshal_signature(&sig_str, ctx.buf)?;
    marshal_param(&var.value, ctx)?;
    Ok(())
}

fn marshal_dict(dict: &params::DictMap, ctx: &mut MarshalContext) -> message::Result<()> {
    ctx.align_to(4);
    let len_pos = ctx.buf.len();
    ctx.buf.push(0);
    ctx.buf.push(0);
    ctx.buf.push(0);
    ctx.buf.push(0);

    // elements are aligned to 8
    ctx.align_to(8);

    let content_pos = ctx.buf.len();
    for (key, value) in dict {
        // elements are aligned to 8
        ctx.align_to(8);
        marshal_base_param(&key, ctx)?;
        marshal_param(&value, ctx)?;
    }
    let len = ctx.buf.len() - content_pos;
    insert_u32(
        ctx.byteorder,
        len as u32,
        &mut ctx.buf[len_pos..len_pos + 4],
    );
    Ok(())
}

pub fn marshal_container_param(
    p: &params::Container,
    ctx: &mut MarshalContext,
) -> message::Result<()> {
    match p {
        params::Container::Array(params) => {
            params::validate_array(&params.values, &params.element_sig)?;
            marshal_array(&params.values, &params.element_sig, ctx)?;
        }
        params::Container::ArrayRef(params) => {
            params::validate_array(&params.values, &params.element_sig)?;
            marshal_array(&params.values, &params.element_sig, ctx)?;
        }
        params::Container::Struct(params) => {
            marshal_struct(params, ctx)?;
        }
        params::Container::StructRef(params) => {
            marshal_struct(params, ctx)?;
        }
        params::Container::Dict(params) => {
            params::validate_dict(&params.map, params.key_sig, &params.value_sig)?;
            marshal_dict(&params.map, ctx)?;
        }
        params::Container::DictRef(params) => {
            params::validate_dict(&params.map, params.key_sig, &params.value_sig)?;
            marshal_dict(params.map, ctx)?;
        }
        params::Container::Variant(variant) => {
            marshal_variant(variant, ctx)?;
        }
    }
    Ok(())
}