Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  attribute.rs   Sprache: unbekannt

 
/* 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 libc::{c_float, size_t};
use std::ptr;
use std::slice;

use nserror::{nsresult, NS_ERROR_INVALID_ARG, NS_OK};
use rsdparsa::attribute_type::*;
use rsdparsa::SdpSession;

use network::{RustAddress, RustExplicitlyTypedAddress};
use types::StringView;

#[no_mangle]
pub unsafe extern "C" fn num_attributes(session: *const SdpSession) -> u32 {
    (*session).attribute.len() as u32
}

#[no_mangle]
pub unsafe extern "C" fn get_attribute_ptr(
    session: *const SdpSession,
    index: u32,
    ret: *mut *const SdpAttribute,
) -> nsresult {
    match (*session).attribute.get(index as usize) {
        Some(attribute) => {
            *ret = attribute as *const SdpAttribute;
            NS_OK
        }
        None => NS_ERROR_INVALID_ARG,
    }
}

fn count_attribute(attributes: &[SdpAttribute], search: SdpAttributeType) -> usize {
    let mut count = 0;
    for attribute in (*attributes).iter() {
        if SdpAttributeType::from(attribute) == search {
            count += 1;
        }
    }
    count
}

fn argsearch(attributes: &[SdpAttribute], attribute_type: SdpAttributeType) -> Option<usize> {
    for (i, attribute) in (*attributes).iter().enumerate() {
        if SdpAttributeType::from(attribute) == attribute_type {
            return Some(i);
        }
    }
    None
}

pub unsafe fn has_attribute(
    attributes: *const Vec<SdpAttribute>,
    attribute_type: SdpAttributeType,
) -> bool {
    argsearch((*attributes).as_slice(), attribute_type).is_some()
}

fn get_attribute(
    attributes: &[SdpAttribute],
    attribute_type: SdpAttributeType,
) -> Option<&SdpAttribute> {
    argsearch(attributes, attribute_type).map(|i| &attributes[i])
}

#[repr(C)]
#[derive(Clone, Copy)]
pub enum RustSdpAttributeDtlsMessageType {
    Client,
    Server,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeDtlsMessage {
    pub role: u8,
    pub value: StringView,
}

impl<'a> From<&'a SdpAttributeDtlsMessage> for RustSdpAttributeDtlsMessage {
    fn from(other: &SdpAttributeDtlsMessage) -> Self {
        match other {
            &SdpAttributeDtlsMessage::Client(ref x) => RustSdpAttributeDtlsMessage {
                role: RustSdpAttributeDtlsMessageType::Client as u8,
                value: StringView::from(x.as_str()),
            },
            &SdpAttributeDtlsMessage::Server(ref x) => RustSdpAttributeDtlsMessage {
                role: RustSdpAttributeDtlsMessageType::Server as u8,
                value: StringView::from(x.as_str()),
            },
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_dtls_message(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut RustSdpAttributeDtlsMessage,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::DtlsMessage);
    if let Some(&SdpAttribute::DtlsMessage(ref dtls_message)) = attr {
        *ret = RustSdpAttributeDtlsMessage::from(dtls_message);
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_iceufrag(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut StringView,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IceUfrag);
    if let Some(&SdpAttribute::IceUfrag(ref string)) = attr {
        *ret = StringView::from(string.as_str());
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_icepwd(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut StringView,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IcePwd);
    if let Some(&SdpAttribute::IcePwd(ref string)) = attr {
        *ret = StringView::from(string.as_str());
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_identity(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut StringView,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Identity);
    if let Some(&SdpAttribute::Identity(ref string)) = attr {
        *ret = StringView::from(string.as_str());
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_iceoptions(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut *const Vec<String>,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::IceOptions);
    if let Some(&SdpAttribute::IceOptions(ref options)) = attr {
        *ret = options;
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_maxptime(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut u64,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::MaxPtime);
    if let Some(&SdpAttribute::MaxPtime(ref max_ptime)) = attr {
        *ret = *max_ptime;
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeFingerprint {
    hash_algorithm: u16,
    fingerprint: *const Vec<u8>,
}

impl<'a> From<&'a SdpAttributeFingerprint> for RustSdpAttributeFingerprint {
    fn from(other: &SdpAttributeFingerprint) -> Self {
        RustSdpAttributeFingerprint {
            hash_algorithm: other.hash_algorithm as u16,
            fingerprint: &other.fingerprint,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_fingerprint_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Fingerprint)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_fingerprints(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_fingerprints: *mut RustSdpAttributeFingerprint,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Fingerprint(ref data) = *x {
                Some(RustSdpAttributeFingerprint::from(data))
            } else {
                None
            }
        })
        .collect();
    let fingerprints = slice::from_raw_parts_mut(ret_fingerprints, ret_size);
    fingerprints.copy_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone)]
pub enum RustSdpAttributeSetup {
    Active,
    Actpass,
    Holdconn,
    Passive,
}

impl<'a> From<&'a SdpAttributeSetup> for RustSdpAttributeSetup {
    fn from(other: &SdpAttributeSetup) -> Self {
        match *other {
            SdpAttributeSetup::Active => RustSdpAttributeSetup::Active,
            SdpAttributeSetup::Actpass => RustSdpAttributeSetup::Actpass,
            SdpAttributeSetup::Holdconn => RustSdpAttributeSetup::Holdconn,
            SdpAttributeSetup::Passive => RustSdpAttributeSetup::Passive,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_setup(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut RustSdpAttributeSetup,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Setup);
    if let Some(&SdpAttribute::Setup(ref setup)) = attr {
        *ret = RustSdpAttributeSetup::from(setup);
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeSsrc {
    pub id: u32,
    pub attribute: StringView,
    pub value: StringView,
}

impl<'a> From<&'a SdpAttributeSsrc> for RustSdpAttributeSsrc {
    fn from(other: &SdpAttributeSsrc) -> Self {
        RustSdpAttributeSsrc {
            id: other.id,
            attribute: StringView::from(&other.attribute),
            value: StringView::from(&other.value),
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_ssrc_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Ssrc)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_ssrcs(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_ssrcs: *mut RustSdpAttributeSsrc,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Ssrc(ref data) = *x {
                Some(RustSdpAttributeSsrc::from(data))
            } else {
                None
            }
        })
        .collect();
    let ssrcs = slice::from_raw_parts_mut(ret_ssrcs, ret_size);
    ssrcs.copy_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub enum RustSdpSsrcGroupSemantic {
    Duplication,
    FlowIdentification,
    ForwardErrorCorrection,
    ForwardErrorCorrectionFr,
    SIM,
}

impl<'a> From<&'a SdpSsrcGroupSemantic> for RustSdpSsrcGroupSemantic {
    fn from(other: &SdpSsrcGroupSemantic) -> Self {
        match *other {
            SdpSsrcGroupSemantic::Duplication => RustSdpSsrcGroupSemantic::Duplication,
            SdpSsrcGroupSemantic::FlowIdentification => {
                RustSdpSsrcGroupSemantic::FlowIdentification
            }
            SdpSsrcGroupSemantic::ForwardErrorCorrection => {
                RustSdpSsrcGroupSemantic::ForwardErrorCorrection
            }
            SdpSsrcGroupSemantic::ForwardErrorCorrectionFr => {
                RustSdpSsrcGroupSemantic::ForwardErrorCorrectionFr
            }
            SdpSsrcGroupSemantic::Sim => RustSdpSsrcGroupSemantic::SIM,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpSsrcGroup {
    pub semantic: RustSdpSsrcGroupSemantic,
    pub ssrcs: *const Vec<SdpAttributeSsrc>,
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_ssrc_group_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::SsrcGroup)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_ssrc_groups(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_ssrc_groups: *mut RustSdpSsrcGroup,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::SsrcGroup(ref semantic, ref ssrcs) = *x {
                Some(RustSdpSsrcGroup {
                    semantic: RustSdpSsrcGroupSemantic::from(semantic),
                    ssrcs: ssrcs,
                })
            } else {
                None
            }
        })
        .collect();
    let ssrc_groups = slice::from_raw_parts_mut(ret_ssrc_groups, ret_size);
    ssrc_groups.copy_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeRtpmap {
    pub payload_type: u8,
    pub codec_name: StringView,
    pub frequency: u32,
    pub channels: u32,
}

impl<'a> From<&'a SdpAttributeRtpmap> for RustSdpAttributeRtpmap {
    fn from(other: &SdpAttributeRtpmap) -> Self {
        RustSdpAttributeRtpmap {
            payload_type: other.payload_type as u8,
            codec_name: StringView::from(other.codec_name.as_str()),
            frequency: other.frequency as u32,
            channels: other.channels.unwrap_or(0),
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_rtpmap_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Rtpmap)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_rtpmaps(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_rtpmaps: *mut RustSdpAttributeRtpmap,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Rtpmap(ref data) = *x {
                Some(RustSdpAttributeRtpmap::from(data))
            } else {
                None
            }
        })
        .collect();
    let rtpmaps = slice::from_raw_parts_mut(ret_rtpmaps, ret_size);
    rtpmaps.copy_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustRtxFmtpParameters {
    pub apt: u8,
    pub has_rtx_time: bool,
    pub rtx_time: u32,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustAv1FmtpParameters {
    pub profile: u8,
    pub has_profile: bool,
    pub level_idx: u8,
    pub has_level_idx: bool,
    pub tier: u8,
    pub has_tier: bool,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeFmtpParameters {
    // H264
    pub packetization_mode: u32,
    pub level_asymmetry_allowed: bool,
    pub profile_level_id: u32,
    pub max_fs: u32,
    pub max_cpb: u32,
    pub max_dpb: u32,
    pub max_br: u32,
    pub max_mbps: u32,

    // VP8 and VP9
    // max_fs, already defined in H264
    pub max_fr: u32,

    // Opus
    pub maxplaybackrate: u32,
    pub maxaveragebitrate: u32,
    pub usedtx: bool,
    pub stereo: bool,
    pub useinbandfec: bool,
    pub cbr: bool,
    pub ptime: u32,
    pub minptime: u32,
    pub maxptime: u32,

    // telephone-event
    pub dtmf_tones: StringView,

    // AV1
    pub av1: RustAv1FmtpParameters,

    // RTX
    pub rtx: RustRtxFmtpParameters,

    // Red
    pub encodings: *const Vec<u8>,

    // Unknown
    pub unknown_tokens: *const Vec<String>,
}

impl<'a> From<&'a SdpAttributeFmtpParameters> for RustSdpAttributeFmtpParameters {
    fn from(other: &SdpAttributeFmtpParameters) -> Self {
        let rtx = if let Some(rtx) = other.rtx {
            RustRtxFmtpParameters {
                apt: rtx.apt,
                has_rtx_time: rtx.rtx_time.is_some(),
                rtx_time: rtx.rtx_time.unwrap_or(0),
            }
        } else {
            RustRtxFmtpParameters {
                apt: 0,
                has_rtx_time: false,
                rtx_time: 0,
            }
        };
        let av1 = RustAv1FmtpParameters {
            profile: other.profile.unwrap_or(0),
            has_profile: other.profile.is_some(),
            level_idx: other.level_idx.unwrap_or(0),
            has_level_idx: other.level_idx.is_some(),
            tier: other.tier.unwrap_or(0),
            has_tier: other.tier.is_some(),
        };

        RustSdpAttributeFmtpParameters {
            packetization_mode: other.packetization_mode,
            level_asymmetry_allowed: other.level_asymmetry_allowed,
            profile_level_id: other.profile_level_id,
            max_fs: other.max_fs,
            max_cpb: other.max_cpb,
            max_dpb: other.max_dpb,
            max_br: other.max_br,
            max_mbps: other.max_mbps,
            usedtx: other.usedtx,
            stereo: other.stereo,
            useinbandfec: other.useinbandfec,
            cbr: other.cbr,
            max_fr: other.max_fr,
            maxplaybackrate: other.maxplaybackrate,
            maxaveragebitrate: other.maxaveragebitrate,
            ptime: other.ptime,
            minptime: other.minptime,
            maxptime: other.maxptime,
            dtmf_tones: StringView::from(other.dtmf_tones.as_str()),
            av1,
            rtx,
            encodings: &other.encodings,
            unknown_tokens: &other.unknown_tokens,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeFmtp {
    pub payload_type: u8,
    pub codec_name: StringView,
    pub parameters: RustSdpAttributeFmtpParameters,
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_fmtp_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Fmtp)
}

fn find_payload_type(attributes: &[SdpAttribute], payload_type: u8) -> Option<&SdpAttributeRtpmap> {
    attributes
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Rtpmap(ref data) = *x {
                if data.payload_type == payload_type {
                    Some(data)
                } else {
                    None
                }
            } else {
                None
            }
        })
        .next()
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_fmtp(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_fmtp: *mut RustSdpAttributeFmtp,
) -> size_t {
    let fmtps = (*attributes).iter().filter_map(|x| {
        if let SdpAttribute::Fmtp(ref data) = *x {
            Some(data)
        } else {
            None
        }
    });
    let mut rust_fmtps = Vec::new();
    for fmtp in fmtps {
        if let Some(rtpmap) = find_payload_type((*attributes).as_slice(), fmtp.payload_type) {
            rust_fmtps.push(RustSdpAttributeFmtp {
                payload_type: fmtp.payload_type as u8,
                codec_name: StringView::from(rtpmap.codec_name.as_str()),
                parameters: RustSdpAttributeFmtpParameters::from(&fmtp.parameters),
            });
        }
    }
    let fmtps = if ret_size <= rust_fmtps.len() {
        slice::from_raw_parts_mut(ret_fmtp, ret_size)
    } else {
        slice::from_raw_parts_mut(ret_fmtp, rust_fmtps.len())
    };
    fmtps.copy_from_slice(rust_fmtps.as_slice());
    fmtps.len()
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_ptime(attributes: *const Vec<SdpAttribute>) -> i64 {
    for attribute in (*attributes).iter() {
        if let SdpAttribute::Ptime(time) = *attribute {
            return time as i64;
        }
    }
    -1
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_max_msg_size(attributes: *const Vec<SdpAttribute>) -> i64 {
    for attribute in (*attributes).iter() {
        if let SdpAttribute::MaxMessageSize(max_msg_size) = *attribute {
            return max_msg_size as i64;
        }
    }
    -1
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_sctp_port(attributes: *const Vec<SdpAttribute>) -> i64 {
    for attribute in (*attributes).iter() {
        if let SdpAttribute::SctpPort(port) = *attribute {
            return port as i64;
        }
    }
    -1
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeFlags {
    pub ice_lite: bool,
    pub rtcp_mux: bool,
    pub rtcp_rsize: bool,
    pub bundle_only: bool,
    pub end_of_candidates: bool,
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_attribute_flags(
    attributes: *const Vec<SdpAttribute>,
) -> RustSdpAttributeFlags {
    let mut ret = RustSdpAttributeFlags {
        ice_lite: false,
        rtcp_mux: false,
        rtcp_rsize: false,
        bundle_only: false,
        end_of_candidates: false,
    };
    for attribute in (*attributes).iter() {
        if let SdpAttribute::IceLite = *attribute {
            ret.ice_lite = true;
        } else if let SdpAttribute::RtcpMux = *attribute {
            ret.rtcp_mux = true;
        } else if let SdpAttribute::RtcpRsize = *attribute {
            ret.rtcp_rsize = true;
        } else if let SdpAttribute::BundleOnly = *attribute {
            ret.bundle_only = true;
        } else if let SdpAttribute::EndOfCandidates = *attribute {
            ret.end_of_candidates = true;
        }
    }
    ret
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_mid(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut StringView,
) -> nsresult {
    for attribute in (*attributes).iter() {
        if let SdpAttribute::Mid(ref data) = *attribute {
            *ret = StringView::from(data.as_str());
            return NS_OK;
        }
    }
    NS_ERROR_INVALID_ARG
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeMsid {
    id: StringView,
    appdata: StringView,
}

impl<'a> From<&'a SdpAttributeMsid> for RustSdpAttributeMsid {
    fn from(other: &SdpAttributeMsid) -> Self {
        RustSdpAttributeMsid {
            id: StringView::from(other.id.as_str()),
            appdata: StringView::from(&other.appdata),
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_msid_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Msid)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_msids(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_msids: *mut RustSdpAttributeMsid,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Msid(ref data) = *x {
                Some(RustSdpAttributeMsid::from(data))
            } else {
                None
            }
        })
        .collect();
    let msids = slice::from_raw_parts_mut(ret_msids, ret_size);
    msids.copy_from_slice(attrs.as_slice());
}

// TODO: Finish msid attributes once parsing is changed upstream.
#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeMsidSemantic {
    pub semantic: StringView,
    pub msids: *const Vec<String>,
}

impl<'a> From<&'a SdpAttributeMsidSemantic> for RustSdpAttributeMsidSemantic {
    fn from(other: &SdpAttributeMsidSemantic) -> Self {
        RustSdpAttributeMsidSemantic {
            semantic: StringView::from(other.semantic.as_str()),
            msids: &other.msids,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_msid_semantic_count(
    attributes: *const Vec<SdpAttribute>,
) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::MsidSemantic)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_msid_semantics(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_msid_semantics: *mut RustSdpAttributeMsidSemantic,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::MsidSemantic(ref data) = *x {
                Some(RustSdpAttributeMsidSemantic::from(data))
            } else {
                None
            }
        })
        .collect();
    let msid_semantics = slice::from_raw_parts_mut(ret_msid_semantics, ret_size);
    msid_semantics.copy_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub enum RustSdpAttributeGroupSemantic {
    LipSynchronization,
    FlowIdentification,
    SingleReservationFlow,
    AlternateNetworkAddressType,
    ForwardErrorCorrection,
    DecodingDependency,
    Bundle,
}

impl<'a> From<&'a SdpAttributeGroupSemantic> for RustSdpAttributeGroupSemantic {
    fn from(other: &SdpAttributeGroupSemantic) -> Self {
        match *other {
            SdpAttributeGroupSemantic::LipSynchronization => {
                RustSdpAttributeGroupSemantic::LipSynchronization
            }
            SdpAttributeGroupSemantic::FlowIdentification => {
                RustSdpAttributeGroupSemantic::FlowIdentification
            }
            SdpAttributeGroupSemantic::SingleReservationFlow => {
                RustSdpAttributeGroupSemantic::SingleReservationFlow
            }
            SdpAttributeGroupSemantic::AlternateNetworkAddressType => {
                RustSdpAttributeGroupSemantic::AlternateNetworkAddressType
            }
            SdpAttributeGroupSemantic::ForwardErrorCorrection => {
                RustSdpAttributeGroupSemantic::ForwardErrorCorrection
            }
            SdpAttributeGroupSemantic::DecodingDependency => {
                RustSdpAttributeGroupSemantic::DecodingDependency
            }
            SdpAttributeGroupSemantic::Bundle => RustSdpAttributeGroupSemantic::Bundle,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeGroup {
    pub semantic: RustSdpAttributeGroupSemantic,
    pub tags: *const Vec<String>,
}

impl<'a> From<&'a SdpAttributeGroup> for RustSdpAttributeGroup {
    fn from(other: &SdpAttributeGroup) -> Self {
        RustSdpAttributeGroup {
            semantic: RustSdpAttributeGroupSemantic::from(&other.semantics),
            tags: &other.tags,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_group_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Group)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_groups(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_groups: *mut RustSdpAttributeGroup,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Group(ref data) = *x {
                Some(RustSdpAttributeGroup::from(data))
            } else {
                None
            }
        })
        .collect();
    let groups = slice::from_raw_parts_mut(ret_groups, ret_size);
    groups.copy_from_slice(attrs.as_slice());
}

#[repr(C)]
pub struct RustSdpAttributeRtcp {
    pub port: u32,
    pub unicast_addr: RustExplicitlyTypedAddress,
    pub has_address: bool,
}

impl<'a> From<&'a SdpAttributeRtcp> for RustSdpAttributeRtcp {
    fn from(other: &SdpAttributeRtcp) -> Self {
        match other.unicast_addr {
            Some(ref address) => RustSdpAttributeRtcp {
                port: other.port as u32,
                unicast_addr: address.into(),
                has_address: true,
            },
            None => RustSdpAttributeRtcp {
                port: other.port as u32,
                unicast_addr: RustExplicitlyTypedAddress::default(),
                has_address: false,
            },
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_rtcp(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut RustSdpAttributeRtcp,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Rtcp);
    if let Some(&SdpAttribute::Rtcp(ref data)) = attr {
        *ret = RustSdpAttributeRtcp::from(data);
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeRtcpFb {
    pub payload_type: u32,
    pub feedback_type: u32,
    pub parameter: StringView,
    pub extra: StringView,
}

impl<'a> From<&'a SdpAttributeRtcpFb> for RustSdpAttributeRtcpFb {
    fn from(other: &SdpAttributeRtcpFb) -> Self {
        RustSdpAttributeRtcpFb {
            payload_type: match other.payload_type {
                SdpAttributePayloadType::Wildcard => u32::max_value(),
                SdpAttributePayloadType::PayloadType(x) => x as u32,
            },
            feedback_type: other.feedback_type.clone() as u32,
            parameter: StringView::from(other.parameter.as_str()),
            extra: StringView::from(other.extra.as_str()),
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_rtcpfb_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Rtcpfb)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_rtcpfbs(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_rtcpfbs: *mut RustSdpAttributeRtcpFb,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Rtcpfb(ref data) = *x {
                Some(RustSdpAttributeRtcpFb::from(data))
            } else {
                None
            }
        })
        .collect();
    let rtcpfbs = slice::from_raw_parts_mut(ret_rtcpfbs, ret_size);
    rtcpfbs.clone_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeImageAttrXyRange {
    // range
    pub min: u32,
    pub max: u32,
    pub step: u32,

    // discrete values
    pub discrete_values: *const Vec<u32>,
}

impl<'a> From<&'a SdpAttributeImageAttrXyRange> for RustSdpAttributeImageAttrXyRange {
    fn from(other: &SdpAttributeImageAttrXyRange) -> Self {
        match other {
            &SdpAttributeImageAttrXyRange::Range(min, max, step) => {
                RustSdpAttributeImageAttrXyRange {
                    min,
                    max,
                    step: step.unwrap_or(1),
                    discrete_values: ptr::null(),
                }
            }
            &SdpAttributeImageAttrXyRange::DiscreteValues(ref discrete_values) => {
                RustSdpAttributeImageAttrXyRange {
                    min: 0,
                    max: 1,
                    step: 1,
                    discrete_values,
                }
            }
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeImageAttrSRange {
    // range
    pub min: c_float,
    pub max: c_float,

    // discrete values
    pub discrete_values: *const Vec<c_float>,
}

impl<'a> From<&'a SdpAttributeImageAttrSRange> for RustSdpAttributeImageAttrSRange {
    fn from(other: &SdpAttributeImageAttrSRange) -> Self {
        match other {
            &SdpAttributeImageAttrSRange::Range(min, max) => RustSdpAttributeImageAttrSRange {
                min,
                max,
                discrete_values: ptr::null(),
            },
            &SdpAttributeImageAttrSRange::DiscreteValues(ref discrete_values) => {
                RustSdpAttributeImageAttrSRange {
                    min: 0.0,
                    max: 1.0,
                    discrete_values,
                }
            }
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeImageAttrPRange {
    pub min: c_float,
    pub max: c_float,
}

impl<'a> From<&'a SdpAttributeImageAttrPRange> for RustSdpAttributeImageAttrPRange {
    fn from(other: &SdpAttributeImageAttrPRange) -> Self {
        RustSdpAttributeImageAttrPRange {
            min: other.min,
            max: other.max,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeImageAttrSet {
    pub x: RustSdpAttributeImageAttrXyRange,
    pub y: RustSdpAttributeImageAttrXyRange,

    pub has_sar: bool,
    pub sar: RustSdpAttributeImageAttrSRange,

    pub has_par: bool,
    pub par: RustSdpAttributeImageAttrPRange,

    pub q: c_float,
}

impl<'a> From<&'a SdpAttributeImageAttrSet> for RustSdpAttributeImageAttrSet {
    fn from(other: &SdpAttributeImageAttrSet) -> Self {
        RustSdpAttributeImageAttrSet {
            x: RustSdpAttributeImageAttrXyRange::from(&other.x),
            y: RustSdpAttributeImageAttrXyRange::from(&other.y),

            has_sar: other.sar.is_some(),
            sar: match other.sar {
                Some(ref x) => RustSdpAttributeImageAttrSRange::from(x),
                // This is just any valid value accepted by rust,
                // it might as well by uninitilized
                None => RustSdpAttributeImageAttrSRange::from(
                    &SdpAttributeImageAttrSRange::DiscreteValues(vec![]),
                ),
            },

            has_par: other.par.is_some(),
            par: match other.par {
                Some(ref x) => RustSdpAttributeImageAttrPRange::from(x),
                // This is just any valid value accepted by rust,
                // it might as well by uninitilized
                None => RustSdpAttributeImageAttrPRange { min: 0.0, max: 1.0 },
            },

            q: other.q.unwrap_or(0.5),
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeImageAttrSetList {
    pub sets: *const Vec<SdpAttributeImageAttrSet>,
}

impl<'a> From<&'a SdpAttributeImageAttrSetList> for RustSdpAttributeImageAttrSetList {
    fn from(other: &SdpAttributeImageAttrSetList) -> Self {
        match other {
            &SdpAttributeImageAttrSetList::Wildcard => {
                RustSdpAttributeImageAttrSetList { sets: ptr::null() }
            }
            &SdpAttributeImageAttrSetList::Sets(ref sets) => {
                RustSdpAttributeImageAttrSetList { sets: sets }
            }
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_imageattr_get_set_count(
    sets: *const Vec<SdpAttributeImageAttrSet>,
) -> size_t {
    (*sets).len()
}

#[no_mangle]
pub unsafe extern "C" fn sdp_imageattr_get_sets(
    sets: *const Vec<SdpAttributeImageAttrSet>,
    ret_size: size_t,
    ret: *mut RustSdpAttributeImageAttrSet,
) {
    let rust_sets: Vec<_> = (*sets)
        .iter()
        .map(RustSdpAttributeImageAttrSet::from)
        .collect();
    let sets = slice::from_raw_parts_mut(ret, ret_size);
    sets.clone_from_slice(rust_sets.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeImageAttr {
    pub pt: u32,
    pub send: RustSdpAttributeImageAttrSetList,
    pub recv: RustSdpAttributeImageAttrSetList,
}

impl<'a> From<&'a SdpAttributeImageAttr> for RustSdpAttributeImageAttr {
    fn from(other: &SdpAttributeImageAttr) -> Self {
        RustSdpAttributeImageAttr {
            pt: match other.pt {
                SdpAttributePayloadType::Wildcard => u32::max_value(),
                SdpAttributePayloadType::PayloadType(x) => x as u32,
            },
            send: RustSdpAttributeImageAttrSetList::from(&other.send),
            recv: RustSdpAttributeImageAttrSetList::from(&other.recv),
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_imageattr_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::ImageAttr)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_imageattrs(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_attrs: *mut RustSdpAttributeImageAttr,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::ImageAttr(ref data) = *x {
                Some(RustSdpAttributeImageAttr::from(data))
            } else {
                None
            }
        })
        .collect();
    let imageattrs = slice::from_raw_parts_mut(ret_attrs, ret_size);
    imageattrs.copy_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeSctpmap {
    pub port: u32,
    pub channels: u32,
}

impl<'a> From<&'a SdpAttributeSctpmap> for RustSdpAttributeSctpmap {
    fn from(other: &SdpAttributeSctpmap) -> Self {
        RustSdpAttributeSctpmap {
            port: other.port as u32,
            channels: other.channels,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_sctpmap_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Sctpmap)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_sctpmaps(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_sctpmaps: *mut RustSdpAttributeSctpmap,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Sctpmap(ref data) = *x {
                Some(RustSdpAttributeSctpmap::from(data))
            } else {
                None
            }
        })
        .collect();
    let sctpmaps = slice::from_raw_parts_mut(ret_sctpmaps, ret_size);
    sctpmaps.copy_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeSimulcastId {
    pub id: StringView,
    pub paused: bool,
}

impl<'a> From<&'a SdpAttributeSimulcastId> for RustSdpAttributeSimulcastId {
    fn from(other: &SdpAttributeSimulcastId) -> Self {
        RustSdpAttributeSimulcastId {
            id: StringView::from(other.id.as_str()),
            paused: other.paused,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeSimulcastVersion {
    pub ids: *const Vec<SdpAttributeSimulcastId>,
}

impl<'a> From<&'a SdpAttributeSimulcastVersion> for RustSdpAttributeSimulcastVersion {
    fn from(other: &SdpAttributeSimulcastVersion) -> Self {
        RustSdpAttributeSimulcastVersion { ids: &other.ids }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_simulcast_get_ids_count(
    ids: *const Vec<SdpAttributeSimulcastId>,
) -> size_t {
    (*ids).len()
}

#[no_mangle]
pub unsafe extern "C" fn sdp_simulcast_get_ids(
    ids: *const Vec<SdpAttributeSimulcastId>,
    ret_size: size_t,
    ret: *mut RustSdpAttributeSimulcastId,
) {
    let rust_ids: Vec<_> = (*ids)
        .iter()
        .map(RustSdpAttributeSimulcastId::from)
        .collect();
    let ids = slice::from_raw_parts_mut(ret, ret_size);
    ids.clone_from_slice(rust_ids.as_slice());
}

#[repr(C)]
pub struct RustSdpAttributeSimulcast {
    pub send: *const Vec<SdpAttributeSimulcastVersion>,
    pub receive: *const Vec<SdpAttributeSimulcastVersion>,
}

impl<'a> From<&'a SdpAttributeSimulcast> for RustSdpAttributeSimulcast {
    fn from(other: &SdpAttributeSimulcast) -> Self {
        RustSdpAttributeSimulcast {
            send: &other.send,
            receive: &other.receive,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_simulcast_get_version_count(
    version_list: *const Vec<SdpAttributeSimulcastVersion>,
) -> size_t {
    (*version_list).len()
}

#[no_mangle]
pub unsafe extern "C" fn sdp_simulcast_get_versions(
    version_list: *const Vec<SdpAttributeSimulcastVersion>,
    ret_size: size_t,
    ret: *mut RustSdpAttributeSimulcastVersion,
) {
    let rust_versions_list: Vec<_> = (*version_list)
        .iter()
        .map(RustSdpAttributeSimulcastVersion::from)
        .collect();
    let versions = slice::from_raw_parts_mut(ret, ret_size);
    versions.clone_from_slice(rust_versions_list.as_slice())
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_simulcast(
    attributes: *const Vec<SdpAttribute>,
    ret: *mut RustSdpAttributeSimulcast,
) -> nsresult {
    let attr = get_attribute((*attributes).as_slice(), SdpAttributeType::Simulcast);
    if let Some(&SdpAttribute::Simulcast(ref data)) = attr {
        *ret = RustSdpAttributeSimulcast::from(data);
        return NS_OK;
    }
    NS_ERROR_INVALID_ARG
}

#[repr(C)]
#[derive(Clone, Copy)]
pub enum RustDirection {
    Recvonly,
    Sendonly,
    Sendrecv,
    Inactive,
}

impl<'a> From<&'a Option<SdpAttributeDirection>> for RustDirection {
    fn from(other: &Option<SdpAttributeDirection>) -> Self {
        match *other {
            Some(ref direction) => match *direction {
                SdpAttributeDirection::Recvonly => RustDirection::Recvonly,
                SdpAttributeDirection::Sendonly => RustDirection::Sendonly,
                SdpAttributeDirection::Sendrecv => RustDirection::Sendrecv,
            },
            None => RustDirection::Inactive,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_direction(attributes: *const Vec<SdpAttribute>) -> RustDirection {
    for attribute in (*attributes).iter() {
        match *attribute {
            SdpAttribute::Recvonly => {
                return RustDirection::Recvonly;
            }
            SdpAttribute::Sendonly => {
                return RustDirection::Sendonly;
            }
            SdpAttribute::Sendrecv => {
                return RustDirection::Sendrecv;
            }
            SdpAttribute::Inactive => {
                return RustDirection::Inactive;
            }
            _ => (),
        }
    }
    RustDirection::Sendrecv
}

#[repr(C)]
pub struct RustSdpAttributeRemoteCandidate {
    pub component: u32,
    pub address: RustAddress,
    pub port: u32,
}

impl<'a> From<&'a SdpAttributeRemoteCandidate> for RustSdpAttributeRemoteCandidate {
    fn from(other: &SdpAttributeRemoteCandidate) -> Self {
        RustSdpAttributeRemoteCandidate {
            component: other.component,
            address: RustAddress::from(&other.address),
            port: other.port,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_remote_candidate_count(
    attributes: *const Vec<SdpAttribute>,
) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::RemoteCandidate)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_remote_candidates(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_candidates: *mut RustSdpAttributeRemoteCandidate,
) {
    let attrs = (*attributes).iter().filter_map(|x| {
        if let SdpAttribute::RemoteCandidate(ref data) = *x {
            Some(RustSdpAttributeRemoteCandidate::from(data))
        } else {
            None
        }
    });
    let candidates = slice::from_raw_parts_mut(ret_candidates, ret_size);
    for (source, destination) in attrs.zip(candidates) {
        *destination = source
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_candidate_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Candidate)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_candidates(
    attributes: *const Vec<SdpAttribute>,
    _ret_size: size_t,
    ret: *mut *const Vec<String>,
) {
    let attr_strings: Vec<String> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Candidate(ref attr) = *x {
                // The serialized attribute starts with "candidate:...", this needs to be removed
                Some(attr.to_string())
            } else {
                None
            }
        })
        .collect();

    *ret = Box::into_raw(Box::from(attr_strings));
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeRidParameters {
    pub max_width: u32,
    pub max_height: u32,
    pub max_fps: u32,
    pub max_fs: u32,
    pub max_br: u32,
    pub max_pps: u32,
    pub unknown: *const Vec<String>,
}

impl<'a> From<&'a SdpAttributeRidParameters> for RustSdpAttributeRidParameters {
    fn from(other: &SdpAttributeRidParameters) -> Self {
        RustSdpAttributeRidParameters {
            max_width: other.max_width,
            max_height: other.max_height,
            max_fps: other.max_fps,
            max_fs: other.max_fs,
            max_br: other.max_br,
            max_pps: other.max_pps,

            unknown: &other.unknown,
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeRid {
    pub id: StringView,
    pub direction: u32,
    pub formats: *const Vec<u16>,
    pub params: RustSdpAttributeRidParameters,
    pub depends: *const Vec<String>,
}

impl<'a> From<&'a SdpAttributeRid> for RustSdpAttributeRid {
    fn from(other: &SdpAttributeRid) -> Self {
        RustSdpAttributeRid {
            id: StringView::from(other.id.as_str()),
            direction: other.direction.clone() as u32,
            formats: &other.formats,
            params: RustSdpAttributeRidParameters::from(&other.params),
            depends: &other.depends,
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_rid_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Rid)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_rids(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_rids: *mut RustSdpAttributeRid,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Rid(ref data) = *x {
                Some(RustSdpAttributeRid::from(data))
            } else {
                None
            }
        })
        .collect();
    let rids = slice::from_raw_parts_mut(ret_rids, ret_size);
    rids.clone_from_slice(attrs.as_slice());
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustSdpAttributeExtmap {
    pub id: u16,
    pub direction_specified: bool,
    pub direction: RustDirection,
    pub url: StringView,
    pub extension_attributes: StringView,
}

impl<'a> From<&'a SdpAttributeExtmap> for RustSdpAttributeExtmap {
    fn from(other: &SdpAttributeExtmap) -> Self {
        let dir = if other.direction.is_some() {
            RustDirection::from(&other.direction)
        } else {
            RustDirection::from(&Some(SdpAttributeDirection::Sendrecv))
        };
        RustSdpAttributeExtmap {
            id: other.id as u16,
            direction_specified: other.direction.is_some(),
            direction: dir,
            url: StringView::from(other.url.as_str()),
            extension_attributes: StringView::from(&other.extension_attributes),
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_extmap_count(attributes: *const Vec<SdpAttribute>) -> size_t {
    count_attribute((*attributes).as_slice(), SdpAttributeType::Extmap)
}

#[no_mangle]
pub unsafe extern "C" fn sdp_get_extmaps(
    attributes: *const Vec<SdpAttribute>,
    ret_size: size_t,
    ret_rids: *mut RustSdpAttributeExtmap,
) {
    let attrs: Vec<_> = (*attributes)
        .iter()
        .filter_map(|x| {
            if let SdpAttribute::Extmap(ref data) = *x {
                Some(RustSdpAttributeExtmap::from(data))
            } else {
                None
            }
        })
        .collect();
    let extmaps = slice::from_raw_parts_mut(ret_rids, ret_size);
    extmaps.copy_from_slice(attrs.as_slice());
}

[ Dauer der Verarbeitung: 0.48 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge