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 121 122 123 124 125 126
use azure::core::errors::AzureError; use azure::storage::blob::BlobBlockType; use azure::storage::blob::BlobBlockWithSize; use base64; use serde_xml_rs::deserialize; use std::borrow::Borrow; #[derive(Debug, Deserialize)] struct Name { #[serde(rename = "$value")] pub value: String, } #[derive(Debug, Deserialize)] struct Size { #[serde(rename = "$value")] pub value: u64, } #[derive(Debug, Deserialize)] struct InnerBlock { #[serde(rename = "Name")] pub name: Name, #[serde(rename = "Size")] pub size: Size, } #[derive(Debug, Deserialize)] struct OuterBlock { #[serde(rename = "Block")] pub block: Option<Vec<InnerBlock>>, } #[derive(Debug, Deserialize)] struct BlockList { #[serde(rename = "CommittedBlocks")] pub committed_blocks: OuterBlock, #[serde(rename = "UncommittedBlocks")] pub uncommitted_blocks: OuterBlock, } #[derive(Default, Debug, Clone, PartialEq)] pub struct BlockWithSizeList<T> where T: Borrow<[u8]>, { pub blocks: Vec<BlobBlockWithSize<T>>, } impl BlockWithSizeList<Vec<u8>> { pub fn try_from(xml: &str) -> Result<BlockWithSizeList<Vec<u8>>, AzureError> { let bl: BlockList = deserialize(xml.as_bytes())?; debug!("bl == {:?}", bl); let mut lbs = BlockWithSizeList { blocks: Vec::new() }; if let Some(b) = bl.committed_blocks.block { for b_val in b { lbs.blocks.push(BlobBlockWithSize { block_list_type: BlobBlockType::Committed(base64::decode(&b_val.name.value)?.to_owned()), size_in_bytes: b_val.size.value, }); } } if let Some(b) = bl.uncommitted_blocks.block { for b_val in b { lbs.blocks.push(BlobBlockWithSize { block_list_type: BlobBlockType::Uncommitted(base64::decode(&b_val.name.value)?.to_owned()), size_in_bytes: b_val.size.value, }); } } Ok(lbs) } } #[cfg(test)] mod test { use super::*; #[test] fn try_parse() { let range = "<?xml version=\"1.0\" encoding=\"utf-8\"?> <BlockList> <CommittedBlocks> <Block> <Name>YmFzZTY0LWVuY29kZWQtYmxvY2staWQ=</Name> <Size>200</Size> </Block> </CommittedBlocks> <UncommittedBlocks> <Block> <Name>YmFzZTY0LWVuY29kZWQtYmxvY2staWQtbnVtYmVyMg==</Name> <Size>4096</Size> </Block> </UncommittedBlocks> </BlockList> "; let bl = BlockWithSizeList::try_from(range).unwrap(); assert!(bl.blocks.len() == 2); assert!(bl.blocks[0].size_in_bytes == 200); assert!(bl.blocks[1].size_in_bytes == 4096); assert!(bl.blocks[0].block_list_type == BlobBlockType::Committed(Vec::from(b"base64-encoded-block-id" as &[u8]))); let b2 = BlobBlockType::Uncommitted(Vec::from(b"base64-encoded-block-id-number2" as &[u8])); assert!( bl.blocks[1].block_list_type == b2, "bl.blocks[1].block_list_type == {:?}, b2 == {:?}", bl.blocks[1].block_list_type, b2 ); } #[test] fn try_parse2() { let range = "<?xml version=\"1.0\" encoding=\"utf-8\"?><BlockList><CommittedBlocks /><UncommittedBlocks><Block><Name>YmxvY2sx</Name><Size>62</Size></Block><Block><Name>YmxvY2sy</Name><Size>62</Size></Block><Block><Name>YmxvY2sz</Name><Size>62</Size></Block></UncommittedBlocks></BlockList>"; let bl = BlockWithSizeList::try_from(range).unwrap(); assert!(bl.blocks.len() == 3); assert!(bl.blocks[0].size_in_bytes == 62); assert!(bl.blocks[1].size_in_bytes == 62); assert!(bl.blocks[2].size_in_bytes == 62); } }