Add ability to create an index

This commit is contained in:
Emi Simpson 2022-08-11 21:41:18 -04:00
parent 8c4336709b
commit a29322f108
Signed by: Emi
GPG Key ID: A12F2C2FFDC3D847
9 changed files with 677 additions and 92 deletions

41
Cargo.lock generated
View File

@ -96,6 +96,7 @@ dependencies = [
"iota-crypto",
"itertools",
"mime",
"protobuf",
"ureq",
"webp",
]
@ -547,6 +548,26 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "protobuf"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee4a7d8b91800c8f167a6268d1a1026607368e1adc84e98fe044aeb905302f7"
dependencies = [
"once_cell",
"protobuf-support",
"thiserror",
]
[[package]]
name = "protobuf-support"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ca157fe12fc7ee2e315f2f735e27df41b3d97cdd70ea112824dac1ffb08ee1c"
dependencies = [
"thiserror",
]
[[package]]
name = "quote"
version = "1.0.21"
@ -633,6 +654,26 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tiff"
version = "0.7.3"

View File

@ -13,6 +13,7 @@ itertools = "0.10.3"
blurhash = "0.1.1"
base64 = "0.13.0"
mime = "0.3.16"
protobuf = "3.1.0"
[dependencies.iota-crypto]
version = "0.13.0"

8
protobuf/image.proto Normal file
View File

@ -0,0 +1,8 @@
syntax = "proto3";
message Image {
bytes key = 1;
string full_url = 2;
string thumb_url = 3;
string blurhash = 4;
}

9
protobuf/index.proto Normal file
View File

@ -0,0 +1,9 @@
syntax = "proto3";
import "image.proto";
message Index {
repeated Image images = 1;
optional string title = 2;
optional string desc = 3;
}

94
src/errors.rs Normal file
View File

@ -0,0 +1,94 @@
use std::{path::{PathBuf, Path}, io};
#[derive(Debug)]
pub enum AviaryError {
/// One of the files passed by the user simply did not exist
///
/// The attached path is the file which didn't exist
///
/// Handling: Halt execution before any upload begins and alert the user of any
/// missing files.
FileDNE(PathBuf),
/// The program lacks permission to read one of the images provided by the user
///
/// Handling: Halt execution before any upload begins and alert the user of the issue
ReadPermissionDenied(PathBuf),
/// There was an issue reading data from the disk
///
/// Handling: Halt execution immediately and alert the user
StreamReadError(PathBuf, io::Error),
/// One or more of the images wasn't correctly encoded
///
/// Handling: Halt execution immediately and ask the user if they're sure the
/// provided file is an image.
ImageFormatError(PathBuf),
/// The server is currently having some difficulties
///
/// Represents a 5XX or 4XX error, as well as any transport error that doesn't seem
/// like it could stem from a network issue.
///
/// Handling: Halt execution and alert the user that the server isn't working at the
/// minute, and ask them to try a different server or try again.
ServerError(String),
/// Couldn't connect to the server
///
/// Indicates that there was some network error which prevented the client from
/// reaching the server.
///
/// Handling: Halt execution and ask the user to check that their computer is
/// connected to the internet, and is not having any DNS issues.
ConnectionError(String),
/// The server URL provided by the user was invalid
///
/// Handling: Halt execution and alert the user that the server url they provided was
/// invalid, including a couple examples
BadServerParameter,
}
impl AviaryError {
pub fn from_open_error(e: io::ErrorKind, location: &Path) -> AviaryError {
match e {
io::ErrorKind::NotFound => AviaryError::FileDNE(location.to_owned()),
io::ErrorKind::PermissionDenied => AviaryError::ReadPermissionDenied(location.to_owned()),
_ => panic!(
"Received an error kind that should be impossible for {}: {:?}",
location.display(),
e
)
}
}
pub fn from_upload_error(err: ureq::Error) -> AviaryError {
match err {
ureq::Error::Status(code, msg) => AviaryError::ServerError(
format!("Error code {} received from server: {}", code,
msg.into_string().unwrap_or(String::new()))),
ureq::Error::Transport(transport) => match transport.kind() {
ureq::ErrorKind::InvalidUrl =>
AviaryError::BadServerParameter,
ureq::ErrorKind::Dns =>
AviaryError::ConnectionError(
format!("DNS issue: {}", transport.message().unwrap_or(""))),
ureq::ErrorKind::Io =>
AviaryError::ConnectionError(
format!("IO issue: {}", transport.message().unwrap_or(""))),
ureq::ErrorKind::ConnectionFailed =>
AviaryError::ConnectionError(
format!("Connection issue: {}", transport.message().unwrap_or(""))),
ureq::ErrorKind::TooManyRedirects =>
AviaryError::ServerError("Too many redirects".to_owned()),
ureq::ErrorKind::BadHeader =>
AviaryError::ServerError("Invalid header from server".to_owned()),
ureq::ErrorKind::BadStatus =>
AviaryError::ServerError("Invalid status from server".to_owned()),
unk => panic!("Unexpected transport error kind {unk}:\n{transport}")
},
}
}
}

View File

@ -2,64 +2,17 @@ mod parse;
mod crypto;
mod upload;
mod thumbnailing;
mod protobuf;
mod errors;
use std::borrow::Cow;
use std::io::{self, ErrorKind, Read};
use std::io::Read;
use std::fs::File;
use std::path::{PathBuf, Path};
use std::path::Path;
use errors::AviaryError;
use itertools::{Itertools, Either};
#[derive(Debug)]
enum AviaryError {
/// One of the files passed by the user simply did not exist
///
/// The attached path is the file which didn't exist
///
/// Handling: Halt execution before any upload begins and alert the user of any
/// missing files.
FileDNE(PathBuf),
/// The program lacks permission to read one of the images provided by the user
///
/// Handling: Halt execution before any upload begins and alert the user of the issue
ReadPermissionDenied(PathBuf),
/// There was an issue reading data from the disk
///
/// Handling: Halt execution immediately and alert the user
StreamReadError(PathBuf, io::Error),
/// One or more of the images wasn't correctly encoded
///
/// Handling: Halt execution immediately and ask the user if they're sure the
/// provided file is an image.
ImageFormatError(PathBuf),
/// The server is currently having some difficulties
///
/// Represents a 5XX or 4XX error, as well as any transport error that doesn't seem
/// like it could stem from a network issue.
///
/// Handling: Halt execution and alert the user that the server isn't working at the
/// minute, and ask them to try a different server or try again.
ServerError(String),
/// Couldn't connect to the server
///
/// Indicates that there was some network error which prevented the client from
/// reaching the server.
///
/// Handling: Halt execution and ask the user to check that their computer is
/// connected to the internet, and is not having any DNS issues.
ConnectionError(String),
/// The server URL provided by the user was invalid
///
/// Handling: Halt execution and alert the user that the server url they provided was
/// invalid, including a couple examples
BadServerParameter,
}
use ::protobuf::Message;
fn trim_url<'a>(base_url: &str, url: &'a str) -> Option<&'a str> {
if url.starts_with(base_url) {
@ -84,16 +37,8 @@ fn main() {
.map(Path::new)
.map(|path| File::open(path)
.map(|file| (path, file))
.map_err(|e| match e.kind() {
ErrorKind::NotFound => AviaryError::FileDNE(path.to_owned()),
ErrorKind::PermissionDenied => AviaryError::ReadPermissionDenied(path.to_owned()),
_ => panic!(
"Received an error kind that should be impossible for {}: {:?}",
path.display(),
e
)
}
))
.map_err(|e| AviaryError::from_open_error(e.kind(), &path))
)
.partition_result();
if !errors.is_empty() {
@ -119,7 +64,7 @@ fn main() {
} else {
Cow::Owned(format!("https://{}", args.server))
};
let upload_records = files.into_iter()
let index_url = files.into_iter()
.map(|(path, mut file)|
(|| {
let mut buff = Vec::with_capacity(file.metadata()?.len() as usize);
@ -146,31 +91,7 @@ fn main() {
.and_then(|thumb_url|
upload::put_data(&agent, &*full_server, &full_img)
.map(|full_url| (key, full_url, thumb_url, blurhash)))
.map_err(|err| match err {
ureq::Error::Status(code, msg) => AviaryError::ServerError(
format!("Error code {} received from server: {}", code,
msg.into_string().unwrap_or(String::new()))),
ureq::Error::Transport(transport) => match transport.kind() {
ureq::ErrorKind::InvalidUrl =>
AviaryError::BadServerParameter,
ureq::ErrorKind::Dns =>
AviaryError::ConnectionError(
format!("DNS issue: {}", transport.message().unwrap_or(""))),
ureq::ErrorKind::Io =>
AviaryError::ConnectionError(
format!("IO issue: {}", transport.message().unwrap_or(""))),
ureq::ErrorKind::ConnectionFailed =>
AviaryError::ConnectionError(
format!("Connection issue: {}", transport.message().unwrap_or(""))),
ureq::ErrorKind::TooManyRedirects =>
AviaryError::ServerError("Too many redirects".to_owned()),
ureq::ErrorKind::BadHeader =>
AviaryError::ServerError("Invalid header from server".to_owned()),
ureq::ErrorKind::BadStatus =>
AviaryError::ServerError("Invalid status from server".to_owned()),
unk => panic!("Unexpected transport error kind {unk}:\n{transport}")
},
})
.map_err(AviaryError::from_upload_error)
))
.map(|r| r.and_then(|(key, full_url, thumb_url, blurhash)| {
let full_trimmed = trim_url(&*full_server, &full_url);
@ -181,10 +102,31 @@ fn main() {
Err(AviaryError::ServerError(format!("Received bad response from server: {}", full_url)))
}
}))
.map_ok(|(key, full_url, thumb_url, blurhash)| protobuf::image::Image {
key: key.into(),
full_url, thumb_url, blurhash,
special_fields: Default::default()
})
.collect::<Result<Vec<_>, _>>()
.and_then(|image_info|{
let index = protobuf::index::Index {
images: image_info,
title: args.title,
desc: None,
special_fields: Default::default()
};
let index_key = crypto::make_key();
let encrypted_index = crypto::encrypt(
&index_key,
&index.write_to_bytes()
.expect("Error serializing protocol buffers")
);
let encoded_key = base64::encode(index_key);
upload::put_data(&agent, &*full_server, &encrypted_index)
.map_err(|e| AviaryError::from_upload_error(e))
.map(|url| format!("{}#{}", url.trim(), &encoded_key))
})
.unwrap();
upload_records.into_iter()
.for_each(|(key, full_url, thumb_url, blurhash)|
println!("{}, {}, {}, {}", base64::encode(key), full_url, thumb_url, blurhash))
println!("Success! {}", index_url);
}
}

251
src/protobuf/image.rs Normal file
View File

@ -0,0 +1,251 @@
// This file is generated by rust-protobuf 3.1.0. Do not edit
// .proto file is parsed by protoc --rust-out=...
// @generated
// https://github.com/rust-lang/rust-clippy/issues/702
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![allow(unused_attributes)]
#![cfg_attr(rustfmt, rustfmt::skip)]
#![allow(box_pointers)]
#![allow(dead_code)]
#![allow(missing_docs)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(trivial_casts)]
#![allow(unused_results)]
#![allow(unused_mut)]
//! Generated file from `image.proto`
/// Generated files are compatible only with the same version
/// of protobuf runtime.
const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_1_0;
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:Image)
pub struct Image {
// message fields
// @@protoc_insertion_point(field:Image.key)
pub key: ::std::vec::Vec<u8>,
// @@protoc_insertion_point(field:Image.full_url)
pub full_url: ::std::string::String,
// @@protoc_insertion_point(field:Image.thumb_url)
pub thumb_url: ::std::string::String,
// @@protoc_insertion_point(field:Image.blurhash)
pub blurhash: ::std::string::String,
// special fields
// @@protoc_insertion_point(special_field:Image.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a Image {
fn default() -> &'a Image {
<Image as ::protobuf::Message>::default_instance()
}
}
impl Image {
pub fn new() -> Image {
::std::default::Default::default()
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(4);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"key",
|m: &Image| { &m.key },
|m: &mut Image| { &mut m.key },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"full_url",
|m: &Image| { &m.full_url },
|m: &mut Image| { &mut m.full_url },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"thumb_url",
|m: &Image| { &m.thumb_url },
|m: &mut Image| { &mut m.thumb_url },
));
fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>(
"blurhash",
|m: &Image| { &m.blurhash },
|m: &mut Image| { &mut m.blurhash },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<Image>(
"Image",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for Image {
const NAME: &'static str = "Image";
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
while let Some(tag) = is.read_raw_tag_or_eof()? {
match tag {
10 => {
self.key = is.read_bytes()?;
},
18 => {
self.full_url = is.read_string()?;
},
26 => {
self.thumb_url = is.read_string()?;
},
34 => {
self.blurhash = is.read_string()?;
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u64 {
let mut my_size = 0;
if !self.key.is_empty() {
my_size += ::protobuf::rt::bytes_size(1, &self.key);
}
if !self.full_url.is_empty() {
my_size += ::protobuf::rt::string_size(2, &self.full_url);
}
if !self.thumb_url.is_empty() {
my_size += ::protobuf::rt::string_size(3, &self.thumb_url);
}
if !self.blurhash.is_empty() {
my_size += ::protobuf::rt::string_size(4, &self.blurhash);
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
if !self.key.is_empty() {
os.write_bytes(1, &self.key)?;
}
if !self.full_url.is_empty() {
os.write_string(2, &self.full_url)?;
}
if !self.thumb_url.is_empty() {
os.write_string(3, &self.thumb_url)?;
}
if !self.blurhash.is_empty() {
os.write_string(4, &self.blurhash)?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
fn special_fields(&self) -> &::protobuf::SpecialFields {
&self.special_fields
}
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
&mut self.special_fields
}
fn new() -> Image {
Image::new()
}
fn clear(&mut self) {
self.key.clear();
self.full_url.clear();
self.thumb_url.clear();
self.blurhash.clear();
self.special_fields.clear();
}
fn default_instance() -> &'static Image {
static instance: Image = Image {
key: ::std::vec::Vec::new(),
full_url: ::std::string::String::new(),
thumb_url: ::std::string::String::new(),
blurhash: ::std::string::String::new(),
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for Image {
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
descriptor.get(|| file_descriptor().message_by_package_relative_name("Image").unwrap()).clone()
}
}
impl ::std::fmt::Display for Image {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for Image {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0bimage.proto\"m\n\x05Image\x12\x10\n\x03key\x18\x01\x20\x01(\x0cR\
\x03key\x12\x19\n\x08full_url\x18\x02\x20\x01(\tR\x07fullUrl\x12\x1b\n\t\
thumb_url\x18\x03\x20\x01(\tR\x08thumbUrl\x12\x1a\n\x08blurhash\x18\x04\
\x20\x01(\tR\x08blurhashJ\x86\x02\n\x06\x12\x04\0\0\x07\x01\n\x08\n\x01\
\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x07\x01\n\n\n\x03\x04\
\0\x01\x12\x03\x02\x08\r\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x08\x16\n\
\x0c\n\x05\x04\0\x02\0\x05\x12\x03\x03\x08\r\n\x0c\n\x05\x04\0\x02\0\x01\
\x12\x03\x03\x0e\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\
\x0b\n\x04\x04\0\x02\x01\x12\x03\x04\x08\x1c\n\x0c\n\x05\x04\0\x02\x01\
\x05\x12\x03\x04\x08\x0e\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\x0f\
\x17\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x04\x1a\x1b\n\x0b\n\x04\x04\0\
\x02\x02\x12\x03\x05\x08\x1d\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x05\
\x08\x0e\n\x0c\n\x05\x04\0\x02\x02\x01\x12\x03\x05\x0f\x18\n\x0c\n\x05\
\x04\0\x02\x02\x03\x12\x03\x05\x1b\x1c\n\x0b\n\x04\x04\0\x02\x03\x12\x03\
\x06\x08\x1c\n\x0c\n\x05\x04\0\x02\x03\x05\x12\x03\x06\x08\x0e\n\x0c\n\
\x05\x04\0\x02\x03\x01\x12\x03\x06\x0f\x17\n\x0c\n\x05\x04\0\x02\x03\x03\
\x12\x03\x06\x1a\x1bb\x06proto3\
";
/// `FileDescriptorProto` object which was a source for this generated file
fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new();
file_descriptor_proto_lazy.get(|| {
::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
})
}
/// `FileDescriptor` object which allows dynamic access to files
pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new();
static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new();
file_descriptor.get(|| {
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
let mut deps = ::std::vec::Vec::with_capacity(0);
let mut messages = ::std::vec::Vec::with_capacity(1);
messages.push(Image::generated_message_descriptor_data());
let mut enums = ::std::vec::Vec::with_capacity(0);
::protobuf::reflect::GeneratedFileDescriptor::new_generated(
file_descriptor_proto(),
deps,
messages,
enums,
)
});
::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor)
})
}

235
src/protobuf/index.rs Normal file
View File

@ -0,0 +1,235 @@
// This file is generated by rust-protobuf 3.1.0. Do not edit
// .proto file is parsed by protoc --rust-out=...
// @generated
// https://github.com/rust-lang/rust-clippy/issues/702
#![allow(unknown_lints)]
#![allow(clippy::all)]
#![allow(unused_attributes)]
#![cfg_attr(rustfmt, rustfmt::skip)]
#![allow(box_pointers)]
#![allow(dead_code)]
#![allow(missing_docs)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(trivial_casts)]
#![allow(unused_results)]
#![allow(unused_mut)]
//! Generated file from `index.proto`
/// Generated files are compatible only with the same version
/// of protobuf runtime.
const _PROTOBUF_VERSION_CHECK: () = ::protobuf::VERSION_3_1_0;
#[derive(PartialEq,Clone,Default,Debug)]
// @@protoc_insertion_point(message:Index)
pub struct Index {
// message fields
// @@protoc_insertion_point(field:Index.images)
pub images: ::std::vec::Vec<super::image::Image>,
// @@protoc_insertion_point(field:Index.title)
pub title: ::std::option::Option<::std::string::String>,
// @@protoc_insertion_point(field:Index.desc)
pub desc: ::std::option::Option<::std::string::String>,
// special fields
// @@protoc_insertion_point(special_field:Index.special_fields)
pub special_fields: ::protobuf::SpecialFields,
}
impl<'a> ::std::default::Default for &'a Index {
fn default() -> &'a Index {
<Index as ::protobuf::Message>::default_instance()
}
}
impl Index {
pub fn new() -> Index {
::std::default::Default::default()
}
fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData {
let mut fields = ::std::vec::Vec::with_capacity(3);
let mut oneofs = ::std::vec::Vec::with_capacity(0);
fields.push(::protobuf::reflect::rt::v2::make_vec_simpler_accessor::<_, _>(
"images",
|m: &Index| { &m.images },
|m: &mut Index| { &mut m.images },
));
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
"title",
|m: &Index| { &m.title },
|m: &mut Index| { &mut m.title },
));
fields.push(::protobuf::reflect::rt::v2::make_option_accessor::<_, _>(
"desc",
|m: &Index| { &m.desc },
|m: &mut Index| { &mut m.desc },
));
::protobuf::reflect::GeneratedMessageDescriptorData::new_2::<Index>(
"Index",
fields,
oneofs,
)
}
}
impl ::protobuf::Message for Index {
const NAME: &'static str = "Index";
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> {
while let Some(tag) = is.read_raw_tag_or_eof()? {
match tag {
10 => {
self.images.push(is.read_message()?);
},
18 => {
self.title = ::std::option::Option::Some(is.read_string()?);
},
26 => {
self.desc = ::std::option::Option::Some(is.read_string()?);
},
tag => {
::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u64 {
let mut my_size = 0;
for value in &self.images {
let len = value.compute_size();
my_size += 1 + ::protobuf::rt::compute_raw_varint64_size(len) + len;
};
if let Some(v) = self.title.as_ref() {
my_size += ::protobuf::rt::string_size(2, &v);
}
if let Some(v) = self.desc.as_ref() {
my_size += ::protobuf::rt::string_size(3, &v);
}
my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields());
self.special_fields.cached_size().set(my_size as u32);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> {
for v in &self.images {
::protobuf::rt::write_message_field_with_cached_size(1, v, os)?;
};
if let Some(v) = self.title.as_ref() {
os.write_string(2, v)?;
}
if let Some(v) = self.desc.as_ref() {
os.write_string(3, v)?;
}
os.write_unknown_fields(self.special_fields.unknown_fields())?;
::std::result::Result::Ok(())
}
fn special_fields(&self) -> &::protobuf::SpecialFields {
&self.special_fields
}
fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields {
&mut self.special_fields
}
fn new() -> Index {
Index::new()
}
fn clear(&mut self) {
self.images.clear();
self.title = ::std::option::Option::None;
self.desc = ::std::option::Option::None;
self.special_fields.clear();
}
fn default_instance() -> &'static Index {
static instance: Index = Index {
images: ::std::vec::Vec::new(),
title: ::std::option::Option::None,
desc: ::std::option::Option::None,
special_fields: ::protobuf::SpecialFields::new(),
};
&instance
}
}
impl ::protobuf::MessageFull for Index {
fn descriptor() -> ::protobuf::reflect::MessageDescriptor {
static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new();
descriptor.get(|| file_descriptor().message_by_package_relative_name("Index").unwrap()).clone()
}
}
impl ::std::fmt::Display for Index {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for Index {
type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage<Self>;
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0bindex.proto\x1a\x0bimage.proto\"n\n\x05Index\x12\x1e\n\x06images\
\x18\x01\x20\x03(\x0b2\x06.ImageR\x06images\x12\x19\n\x05title\x18\x02\
\x20\x01(\tH\0R\x05title\x88\x01\x01\x12\x17\n\x04desc\x18\x03\x20\x01(\
\tH\x01R\x04desc\x88\x01\x01B\x08\n\x06_titleB\x07\n\x05_descJ\x84\x02\n\
\x06\x12\x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\t\n\x02\x03\0\
\x12\x03\x02\0\x15\n\n\n\x02\x04\0\x12\x04\x04\0\x08\x01\n\n\n\x03\x04\0\
\x01\x12\x03\x04\x08\r\n\x0b\n\x04\x04\0\x02\0\x12\x03\x05\x08\"\n\x0c\n\
\x05\x04\0\x02\0\x04\x12\x03\x05\x08\x10\n\x0c\n\x05\x04\0\x02\0\x06\x12\
\x03\x05\x11\x16\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x05\x17\x1d\n\x0c\n\
\x05\x04\0\x02\0\x03\x12\x03\x05\x20!\n\x0b\n\x04\x04\0\x02\x01\x12\x03\
\x06\x08\"\n\x0c\n\x05\x04\0\x02\x01\x04\x12\x03\x06\x08\x10\n\x0c\n\x05\
\x04\0\x02\x01\x05\x12\x03\x06\x11\x17\n\x0c\n\x05\x04\0\x02\x01\x01\x12\
\x03\x06\x18\x1d\n\x0c\n\x05\x04\0\x02\x01\x03\x12\x03\x06\x20!\n\x0b\n\
\x04\x04\0\x02\x02\x12\x03\x07\x08!\n\x0c\n\x05\x04\0\x02\x02\x04\x12\
\x03\x07\x08\x10\n\x0c\n\x05\x04\0\x02\x02\x05\x12\x03\x07\x11\x17\n\x0c\
\n\x05\x04\0\x02\x02\x01\x12\x03\x07\x18\x1c\n\x0c\n\x05\x04\0\x02\x02\
\x03\x12\x03\x07\x1f\x20b\x06proto3\
";
/// `FileDescriptorProto` object which was a source for this generated file
fn file_descriptor_proto() -> &'static ::protobuf::descriptor::FileDescriptorProto {
static file_descriptor_proto_lazy: ::protobuf::rt::Lazy<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::Lazy::new();
file_descriptor_proto_lazy.get(|| {
::protobuf::Message::parse_from_bytes(file_descriptor_proto_data).unwrap()
})
}
/// `FileDescriptor` object which allows dynamic access to files
pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor {
static generated_file_descriptor_lazy: ::protobuf::rt::Lazy<::protobuf::reflect::GeneratedFileDescriptor> = ::protobuf::rt::Lazy::new();
static file_descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::FileDescriptor> = ::protobuf::rt::Lazy::new();
file_descriptor.get(|| {
let generated_file_descriptor = generated_file_descriptor_lazy.get(|| {
let mut deps = ::std::vec::Vec::with_capacity(1);
deps.push(super::image::file_descriptor().clone());
let mut messages = ::std::vec::Vec::with_capacity(1);
messages.push(Index::generated_message_descriptor_data());
let mut enums = ::std::vec::Vec::with_capacity(0);
::protobuf::reflect::GeneratedFileDescriptor::new_generated(
file_descriptor_proto(),
deps,
messages,
enums,
)
});
::protobuf::reflect::FileDescriptor::new_generated_2(generated_file_descriptor)
})
}

4
src/protobuf/mod.rs Normal file
View File

@ -0,0 +1,4 @@
// @generated
pub mod image;
pub mod index;