chore: initial commit
This commit is contained in:
commit
b538545f67
|
@ -0,0 +1,3 @@
|
||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
|
@ -0,0 +1,22 @@
|
||||||
|
cargo-features = ["edition"]
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "lodestone_scraper"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Kyle Clemens <git@kyleclemens.com>"]
|
||||||
|
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
reqwest = "0.8"
|
||||||
|
failure = "0.1"
|
||||||
|
lazy_static = "1"
|
||||||
|
url = "1"
|
||||||
|
|
||||||
|
[dependencies.lodestone_parser]
|
||||||
|
git = "https://github.com/jkcclemens/lodestone_parser"
|
||||||
|
|
||||||
|
[dependencies.ffxiv_types]
|
||||||
|
version = "1"
|
||||||
|
default-features = false
|
||||||
|
features = ["worlds", "data_centers", "races", "clans"]
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018 Kyle Clemens
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod character_search;
|
||||||
|
pub mod free_company_search;
|
||||||
|
|
||||||
|
pub use self::character_search::CharacterSearchBuilder;
|
||||||
|
pub use self::free_company_search::FreeCompanySearchBuilder;
|
|
@ -0,0 +1,135 @@
|
||||||
|
use crate::{
|
||||||
|
LodestoneScraper,
|
||||||
|
error::*,
|
||||||
|
models::ClassJobRole,
|
||||||
|
util::{Either, AsLodestone},
|
||||||
|
};
|
||||||
|
|
||||||
|
use ffxiv_types::{World, Race, Clan, DataCenter};
|
||||||
|
|
||||||
|
use lodestone_parser::models::{
|
||||||
|
GrandCompany,
|
||||||
|
character::Job,
|
||||||
|
search::{
|
||||||
|
Paginated,
|
||||||
|
character::CharacterSearchItem,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CharacterSearchBuilder<'a> {
|
||||||
|
scraper: &'a LodestoneScraper,
|
||||||
|
// q
|
||||||
|
name: Option<&'a str>,
|
||||||
|
// worldname
|
||||||
|
world: Option<Either<World, DataCenter>>,
|
||||||
|
// classjob
|
||||||
|
job: Option<Either<Job, ClassJobRole>>,
|
||||||
|
// race_tribe
|
||||||
|
race: Option<Either<Race, Clan>>,
|
||||||
|
// gcid
|
||||||
|
grand_company: Option<Vec<GrandCompany>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> CharacterSearchBuilder<'a> {
|
||||||
|
pub fn new(scraper: &'a LodestoneScraper) -> Self {
|
||||||
|
CharacterSearchBuilder {
|
||||||
|
scraper,
|
||||||
|
name: None,
|
||||||
|
world: None,
|
||||||
|
job: None,
|
||||||
|
race: None,
|
||||||
|
grand_company: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&mut self, n: &'a str) -> &mut Self {
|
||||||
|
self.name = Some(n);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn world(&mut self, w: World) -> &mut Self {
|
||||||
|
self.world = Some(Either::Left(w));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_center(&mut self, dc: DataCenter) -> &mut Self {
|
||||||
|
self.world = Some(Either::Right(dc));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn job(&mut self, j: Job) -> &mut Self {
|
||||||
|
self.job = Some(Either::Left(j));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn role(&mut self, r: ClassJobRole) -> &mut Self {
|
||||||
|
self.job = Some(Either::Right(r));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn race(&mut self, r: Race) -> &mut Self {
|
||||||
|
self.race = Some(Either::Left(r));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clan(&mut self, c: Clan) -> &mut Self {
|
||||||
|
self.race = Some(Either::Right(c));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grand_company(&mut self, gc: GrandCompany) -> &mut Self {
|
||||||
|
self.grand_company.get_or_insert_with(Default::default).push(gc);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(&self) -> Result<Paginated<CharacterSearchItem>> {
|
||||||
|
let text = self.scraper.client
|
||||||
|
.get(self.as_url())
|
||||||
|
.send()
|
||||||
|
.map_err(Error::Net)?
|
||||||
|
.text()
|
||||||
|
.map_err(Error::Net)?;
|
||||||
|
lodestone_parser::parse_character_search(&text).map_err(Error::Parse)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_url(&self) -> Url {
|
||||||
|
let mut url = crate::LODESTONE_URL.join("character/").unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut pairs = url.query_pairs_mut();
|
||||||
|
|
||||||
|
if let Some(ref name) = self.name {
|
||||||
|
pairs.append_pair("q", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.world {
|
||||||
|
Some(Either::Left(w)) => { pairs.append_pair("worldname", w.as_str()); },
|
||||||
|
Some(Either::Right(dc)) => { pairs.append_pair("worldname", &dc.as_lodestone()); },
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.job {
|
||||||
|
Some(Either::Left(j)) => { pairs.append_pair("classjob", &j.as_lodestone().to_string()); },
|
||||||
|
Some(Either::Right(cjr)) => { pairs.append_pair("classjob", cjr.as_lodestone()); },
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.race {
|
||||||
|
Some(Either::Left(r)) => { pairs.append_pair("race_tribe", &format!("race_{}", r.as_lodestone())); },
|
||||||
|
Some(Either::Right(c)) => { pairs.append_pair("race_tribe", &format!("tribe_{}", c.as_lodestone())); },
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref gcs) = self.grand_company {
|
||||||
|
for gc in gcs {
|
||||||
|
pairs.append_pair("gcid", &gc.as_lodestone().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
use crate::{
|
||||||
|
LodestoneScraper,
|
||||||
|
error::*,
|
||||||
|
util::{Either, AsLodestone},
|
||||||
|
};
|
||||||
|
|
||||||
|
use ffxiv_types::{World, DataCenter};
|
||||||
|
|
||||||
|
use lodestone_parser::models::{
|
||||||
|
GrandCompany,
|
||||||
|
search::{
|
||||||
|
Paginated,
|
||||||
|
free_company::FreeCompanySearchItem,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FreeCompanySearchBuilder<'a> {
|
||||||
|
scraper: &'a LodestoneScraper,
|
||||||
|
// q
|
||||||
|
name: Option<&'a str>,
|
||||||
|
// worldname
|
||||||
|
world: Option<Either<World, DataCenter>>,
|
||||||
|
// gcid
|
||||||
|
grand_company: Option<Vec<GrandCompany>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> FreeCompanySearchBuilder<'a> {
|
||||||
|
pub fn new(scraper: &'a LodestoneScraper) -> Self {
|
||||||
|
FreeCompanySearchBuilder {
|
||||||
|
scraper,
|
||||||
|
name: None,
|
||||||
|
world: None,
|
||||||
|
grand_company: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn name(&mut self, n: &'a str) -> &mut Self {
|
||||||
|
self.name = Some(n);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn world(&mut self, w: World) -> &mut Self {
|
||||||
|
self.world = Some(Either::Left(w));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_center(&mut self, dc: DataCenter) -> &mut Self {
|
||||||
|
self.world = Some(Either::Right(dc));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn grand_company(&mut self, gc: GrandCompany) -> &mut Self {
|
||||||
|
self.grand_company.get_or_insert_with(Default::default).push(gc);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send(&self) -> Result<Paginated<FreeCompanySearchItem>> {
|
||||||
|
let text = self.scraper.client
|
||||||
|
.get(self.as_url())
|
||||||
|
.send()
|
||||||
|
.map_err(Error::Net)?
|
||||||
|
.text()
|
||||||
|
.map_err(Error::Net)?;
|
||||||
|
lodestone_parser::parse_free_company_search(&text).map_err(Error::Parse)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_url(&self) -> Url {
|
||||||
|
let mut url = crate::LODESTONE_URL.join("freecompany/").unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut pairs = url.query_pairs_mut();
|
||||||
|
|
||||||
|
if let Some(ref name) = self.name {
|
||||||
|
pairs.append_pair("q", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.world {
|
||||||
|
Some(Either::Left(w)) => { pairs.append_pair("worldname", w.as_str()); },
|
||||||
|
Some(Either::Right(dc)) => { pairs.append_pair("worldname", &dc.as_lodestone()); },
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref gcs) = self.grand_company {
|
||||||
|
for gc in gcs {
|
||||||
|
pairs.append_pair("gcid", &gc.as_lodestone().to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(Debug, Fail)]
|
||||||
|
pub enum Error {
|
||||||
|
#[fail(display = "network error: {}", _0)]
|
||||||
|
Net(reqwest::Error),
|
||||||
|
#[fail(display = "url parse error: {}", _0)]
|
||||||
|
Url(url::ParseError),
|
||||||
|
#[fail(display = "lodestone parse error: {}", _0)]
|
||||||
|
Parse(lodestone_parser::error::Error),
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
#[macro_use] extern crate failure;
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
|
||||||
|
use lodestone_parser::models::{
|
||||||
|
character::Character,
|
||||||
|
free_company::FreeCompany,
|
||||||
|
};
|
||||||
|
|
||||||
|
use reqwest::Client;
|
||||||
|
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
pub mod builder;
|
||||||
|
pub mod error;
|
||||||
|
pub mod models;
|
||||||
|
crate mod util;
|
||||||
|
|
||||||
|
use crate::error::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LodestoneScraper {
|
||||||
|
client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for LodestoneScraper {
|
||||||
|
fn default() -> Self {
|
||||||
|
let client = Client::new();
|
||||||
|
LodestoneScraper { client }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref LODESTONE_URL: Url = Url::from_str("https://na.finalfantasyxiv.com/lodestone/").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LodestoneScraper {
|
||||||
|
fn route(s: &str) -> Result<Url> {
|
||||||
|
LODESTONE_URL.join(s).map_err(Error::Url)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn character(&self, id: u64) -> Result<Character> {
|
||||||
|
let url = LodestoneScraper::route(&format!("character/{}", id))?;
|
||||||
|
let text = self.client
|
||||||
|
.get(url)
|
||||||
|
.send()
|
||||||
|
.map_err(Error::Net)?
|
||||||
|
.text()
|
||||||
|
.map_err(Error::Net)?;
|
||||||
|
lodestone_parser::parse_character(id, &text).map_err(Error::Parse)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn character_search(&self) -> builder::CharacterSearchBuilder {
|
||||||
|
builder::CharacterSearchBuilder::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_company(&self, id: u64) -> Result<FreeCompany> {
|
||||||
|
let url = LodestoneScraper::route(&format!("freecompany/{}", id))?;
|
||||||
|
let text = self.client
|
||||||
|
.get(url)
|
||||||
|
.send()
|
||||||
|
.map_err(Error::Net)?
|
||||||
|
.text()
|
||||||
|
.map_err(Error::Net)?;
|
||||||
|
lodestone_parser::parse_free_company(id, &text).map_err(Error::Parse)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free_company_search(&self) -> builder::FreeCompanySearchBuilder {
|
||||||
|
builder::FreeCompanySearchBuilder::new(self)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
pub mod class_job_role;
|
||||||
|
|
||||||
|
pub use self::class_job_role::ClassJobRole;
|
|
@ -0,0 +1,13 @@
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum ClassJobRole {
|
||||||
|
ClassTank,
|
||||||
|
ClassHealer,
|
||||||
|
ClassDps,
|
||||||
|
|
||||||
|
JobTank,
|
||||||
|
JobHealer,
|
||||||
|
JobDps,
|
||||||
|
|
||||||
|
ClassDiscipleOfTheHand,
|
||||||
|
ClassDiscipleOfTheLand,
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
crate mod as_lodestone;
|
||||||
|
crate mod either;
|
||||||
|
|
||||||
|
crate use self::as_lodestone::AsLodestone;
|
||||||
|
crate use self::either::Either;
|
|
@ -0,0 +1,131 @@
|
||||||
|
use crate::models::ClassJobRole;
|
||||||
|
|
||||||
|
use ffxiv_types::{DataCenter, Race, Clan};
|
||||||
|
|
||||||
|
use lodestone_parser::models::{
|
||||||
|
GrandCompany,
|
||||||
|
character::Job,
|
||||||
|
};
|
||||||
|
|
||||||
|
crate trait AsLodestone {
|
||||||
|
type Representation;
|
||||||
|
|
||||||
|
fn as_lodestone(&self) -> Self::Representation;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsLodestone for DataCenter {
|
||||||
|
type Representation = String;
|
||||||
|
|
||||||
|
fn as_lodestone(&self) -> Self::Representation {
|
||||||
|
format!("_dc_{}", self.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsLodestone for ClassJobRole {
|
||||||
|
type Representation = &'static str;
|
||||||
|
|
||||||
|
fn as_lodestone(&self) -> Self::Representation {
|
||||||
|
match *self {
|
||||||
|
ClassJobRole::ClassTank => "_class_TANK",
|
||||||
|
ClassJobRole::ClassHealer => "_class_HEALER",
|
||||||
|
ClassJobRole::ClassDps => "_class_DPS",
|
||||||
|
ClassJobRole::JobTank => "_job_TANK",
|
||||||
|
ClassJobRole::JobHealer => "_job_HEALER",
|
||||||
|
ClassJobRole::JobDps => "_job_DPS",
|
||||||
|
ClassJobRole::ClassDiscipleOfTheHand => "_class_CRAFTER",
|
||||||
|
ClassJobRole::ClassDiscipleOfTheLand => "_class_GATHERER",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsLodestone for Job {
|
||||||
|
type Representation = u8;
|
||||||
|
|
||||||
|
fn as_lodestone(&self) -> Self::Representation {
|
||||||
|
match *self {
|
||||||
|
Job::Gladiator => 1,
|
||||||
|
Job::Pugilist => 2,
|
||||||
|
Job::Marauder => 3,
|
||||||
|
Job::Lancer => 4,
|
||||||
|
Job::Archer => 5,
|
||||||
|
Job::Conjurer => 6,
|
||||||
|
Job::Thaumaturge => 7,
|
||||||
|
Job::Carpenter => 8,
|
||||||
|
Job::Blacksmith => 9,
|
||||||
|
Job::Armorer => 10,
|
||||||
|
Job::Goldsmith => 11,
|
||||||
|
Job::Leatherworker => 12,
|
||||||
|
Job::Weaver => 13,
|
||||||
|
Job::Alchemist => 14,
|
||||||
|
Job::Culinarian => 15,
|
||||||
|
Job::Miner => 16,
|
||||||
|
Job::Botanist => 17,
|
||||||
|
Job::Fisher => 18,
|
||||||
|
Job::Paladin => 19,
|
||||||
|
Job::Monk => 20,
|
||||||
|
Job::Warrior => 21,
|
||||||
|
Job::Dragoon => 22,
|
||||||
|
Job::Bard => 23,
|
||||||
|
Job::WhiteMage => 24,
|
||||||
|
Job::BlackMage => 25,
|
||||||
|
Job::Arcanist => 26,
|
||||||
|
Job::Summoner => 27,
|
||||||
|
Job::Scholar => 28,
|
||||||
|
Job::Rogue => 29,
|
||||||
|
Job::Ninja => 30,
|
||||||
|
Job::Machinist => 31,
|
||||||
|
Job::DarkKnight => 32,
|
||||||
|
Job::Astrologian => 33,
|
||||||
|
Job::Samurai => 34,
|
||||||
|
Job::RedMage => 35,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsLodestone for GrandCompany {
|
||||||
|
type Representation = u8;
|
||||||
|
|
||||||
|
fn as_lodestone(&self) -> Self::Representation {
|
||||||
|
match *self {
|
||||||
|
GrandCompany::Maelstrom => 1,
|
||||||
|
GrandCompany::TwinAdders => 2,
|
||||||
|
GrandCompany::Flames => 3,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsLodestone for Race {
|
||||||
|
type Representation = u8;
|
||||||
|
|
||||||
|
fn as_lodestone(&self) -> Self::Representation {
|
||||||
|
match *self {
|
||||||
|
Race::Hyur => 1,
|
||||||
|
Race::Elezen => 2,
|
||||||
|
Race::Lalafell => 3,
|
||||||
|
Race::Miqote => 4,
|
||||||
|
Race::Roegadyn => 5,
|
||||||
|
Race::AuRa => 6,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsLodestone for Clan {
|
||||||
|
type Representation = u8;
|
||||||
|
|
||||||
|
fn as_lodestone(&self) -> Self::Representation {
|
||||||
|
match *self {
|
||||||
|
Clan::Midlander => 1,
|
||||||
|
Clan::Highlander => 2,
|
||||||
|
Clan::Wildwood => 3,
|
||||||
|
Clan::Duskwight => 4,
|
||||||
|
Clan::Plainsfolk => 5,
|
||||||
|
Clan::Dunesfolk => 6,
|
||||||
|
Clan::SeekerOfTheSun => 7,
|
||||||
|
Clan::KeeperOfTheMoon => 8,
|
||||||
|
Clan::SeaWolf => 9,
|
||||||
|
Clan::Hellsguard => 10,
|
||||||
|
Clan::Raen => 11,
|
||||||
|
Clan::Xaela => 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
crate enum Either<L, R> {
|
||||||
|
Left(L),
|
||||||
|
Right(R),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L, R> std::fmt::Debug for Either<L, R>
|
||||||
|
where L: std::fmt::Debug,
|
||||||
|
R: std::fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Either::Left(ref l) => f.debug_tuple("Left").field(l).finish(),
|
||||||
|
Either::Right(ref r) => f.debug_tuple("Right").field(r).finish(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue