From 91d6c2be290e499935cb6d5a8532b6a0614c68cb Mon Sep 17 00:00:00 2001 From: yanorei32 Date: Wed, 12 Apr 2023 19:52:02 +0900 Subject: [PATCH] first commit --- .cargo/config.toml | 3 + .gitignore | 2 + Cargo.lock | 393 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 17 ++ LICENSE | 0 install.nsi | 77 +++++++++ src/main.rs | 85 ++++++++++ src/model.rs | 114 +++++++++++++ 8 files changed, 691 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 LICENSE create mode 100644 install.nsi create mode 100644 src/main.rs create mode 100644 src/model.rs diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..58d9780 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,3 @@ +[build] +target = "x86_64-pc-windows-gnu" + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36d1b46 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +*.exe diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b9ed8d7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,393 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-wincon", + "concolor-override", + "concolor-query", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" + +[[package]] +name = "anstyle-parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-wincon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +dependencies = [ + "anstyle", + "windows-sys 0.45.0", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "clap" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" +dependencies = [ + "clap_builder", + "clap_derive", + "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" + +[[package]] +name = "concolor-override" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" + +[[package]] +name = "concolor-query" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" +dependencies = [ + "windows-sys 0.45.0", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "libc" +version = "0.2.141" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" + +[[package]] +name = "linux-raw-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f" + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "proc-macro2" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustix" +version = "0.37.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winresutil" +version = "0.1.0" +dependencies = [ + "clap", + "winsafe", +] + +[[package]] +name = "winsafe" +version = "0.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62a4f20d0e60f34bfbb2624564d0bfda0a6eaee8f7f4494e5c3c883c3a62fdd2" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4c4c985 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "winresutil" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +winsafe = { version = "0.0.15", features = ["user", "kernel"] } +clap = { version = "4.2.1", features = ["derive"] } + +[profile.release] +opt-level = "z" +debug = false +lto = true +strip = true +codegen-units = 1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e69de29 diff --git a/install.nsi b/install.nsi new file mode 100644 index 0000000..7ac30ef --- /dev/null +++ b/install.nsi @@ -0,0 +1,77 @@ +!include "MUI2.nsh" + +; General + Name "winresutil" + OutFile "winresutil.installer.exe" + Unicode True + + InstallDir "$LOCALAPPDATA\winresutil" + InstallDirRegKey HKCU "Software\winresutil" "" + + RequestExecutionLevel user + +; Compress + SetCompressor /SOLID lzma + SetDatablockOptimize ON + +; Interface + !define MUI_ABORTWARNING + +; Pages + !insertmacro MUI_PAGE_WELCOME + !insertmacro MUI_PAGE_LICENSE "LICENSE" + !insertmacro MUI_PAGE_DIRECTORY + !insertmacro MUI_PAGE_INSTFILES + !insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_WELCOME + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + !insertmacro MUI_UNPAGE_FINISH + +; Registry + !define REGPATH_UNINSTSUBKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\winresutil" + +; Languages + !insertmacro MUI_LANGUAGE "English" + +; Installer Sections +Section "Install" + ReadRegStr $0 HKCU "${REGPATH_UNINSTSUBKEY}" "QuietUninstallString" + ReadRegStr $1 HKCU "${REGPATH_UNINSTSUBKEY}" "InstDir" + StrCmp $0 "" uninstall.done + ExecWait '$0 _?=$1' +uninstall.done: + ; Check for write access + SectionIn RO + SetOutPath "$INSTDIR\bin" + File "target\x86_64-pc-windows-gnu\release\winresutil.exe" + WriteRegStr HKCU "Software\winresutil" "" $INSTDIR + SetOutPath "$INSTDIR" + WriteUninstaller "$INSTDIR\uninstall.exe" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "DisplayName" "winresutil" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "Publisher" "yanorei32" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "Readme" "https://github.com/yanorei32/winresutil" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "URLUpdateInfo" "https://github.com/yanorei32/winresutil/releases" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "URLInfoAbout" "https://github.com/yanorei32/winresutil" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "HelpLink" "https://twitter.com/yanorei32" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "Comments" "This software helps change the window resolution." + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "DisplayIcon" "$INSTDIR\winresutil.exe,0" + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "UninstallString" '"$INSTDIR\uninstall.exe"' + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "QuietUninstallString" '"$INSTDIR\uninstall.exe" /S' + WriteRegStr HKCU "${REGPATH_UNINSTSUBKEY}" "InstDir" '$INSTDIR' + WriteRegDWORD HKCU "${REGPATH_UNINSTSUBKEY}" "EstimatedSize" 192 + WriteRegDWORD HKCU "${REGPATH_UNINSTSUBKEY}" "NoModify" 1 + WriteRegDWORD HKCU "${REGPATH_UNINSTSUBKEY}" "NoRepair" 1 + EnVar::AddValue "path" "$INSTDIR\bin" +SectionEnd + +; Uninstall Sections +Section "Uninstall" + EnVar::DeleteValue "path" "$INSTDIR\bin" + Delete "$INSTDIR\bin\winresutil.exe" + RMDir "$INSTDIR\bin" + Delete "$INSTDIR\uninstall.exe" + RMDir "$INSTDIR" + DeleteRegKey HKCU "${REGPATH_UNINSTSUBKEY}" +SectionEnd diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..f0b95a7 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,85 @@ +use clap::Parser; +use winsafe::{ + co::{PROCESS, PROCESS_NAME, SWP}, + prelude::*, + EnumWindows, HwndPlace, HPROCESS, HWND, POINT, +}; + +mod model; +use model::*; + +fn filter_target_windows(hwnd: &HWND, q: &TargetInformation) -> bool { + if !q.title_contains.is_empty() { + let Ok(title) = hwnd.GetWindowText() else { + return false; + }; + + if q.title_contains.iter().all(|s| !title.contains(s)) { + return false; + } + } + + if !q.path_endswith.is_empty() { + let (_, pid) = hwnd.GetWindowThreadProcessId(); + + let Ok(proc) = HPROCESS::OpenProcess(PROCESS::QUERY_LIMITED_INFORMATION, false, pid) else { + return false; + }; + + let Ok(path) = proc.QueryFullProcessImageName(PROCESS_NAME::WIN32) else { + return false; + }; + + if q.path_endswith.iter().all(|s| !path.ends_with(s)) { + return false; + } + } + + true +} + +fn window_callback(hwnd: HWND, op: &Commands) { + let t = match op { + Commands::Get { target } => target, + Commands::Set { + target, + resolution: _, + } => target, + }; + + if !filter_target_windows(&hwnd, t) { + return; + } + + let client_size = Size::from(hwnd.GetClientRect().unwrap()); + + match op { + Commands::Get { target: _ } => { + println!("{}", client_size - t.offset); + } + Commands::Set { + target: _, + resolution, + } => { + let window_size = Size::from(hwnd.GetWindowRect().unwrap()); + let border = window_size - client_size; + + hwnd.SetWindowPos( + HwndPlace::None, + POINT::new(0, 0), + (*resolution + t.offset + border).into(), + SWP::NOMOVE, + ) + .unwrap(); + } + } +} + +fn main() { + let c = Cli::parse().command; + EnumWindows(|hwnd: HWND| -> bool { + window_callback(hwnd, &c); + true + }) + .unwrap(); +} diff --git a/src/model.rs b/src/model.rs new file mode 100644 index 0000000..ece4c57 --- /dev/null +++ b/src/model.rs @@ -0,0 +1,114 @@ +use clap::{Args, Parser, Subcommand}; +use std::fmt::{self, Display}; +use std::io::{Error, ErrorKind}; +use std::ops::{Add, Sub}; +use winsafe::{RECT, SIZE}; + +#[derive(Debug, Clone, Args)] +pub struct TargetInformation { + #[arg(short, long)] + pub path_endswith: Vec, + #[arg(short, long)] + pub title_contains: Vec, + #[arg(short, long, value_parser = parse_size, default_value_t = Size::default())] + pub offset: Size, +} + +#[derive(Debug, Clone, Subcommand)] +pub enum Commands { + Get { + #[command(flatten)] + target: TargetInformation, + }, + Set { + #[command(flatten)] + target: TargetInformation, + #[arg(value_parser = parse_size)] + resolution: Size, + }, +} + +#[derive(Debug, Parser)] +pub struct Cli { + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Debug, Copy, Clone, Parser)] +pub struct Size { + pub x: usize, + pub y: usize, +} + +impl Add for Size { + type Output = Size; + fn add(self, other: Self) -> Self { + Self { + x: self.x + other.x, + y: self.y + other.y, + } + } +} + +impl Sub for Size { + type Output = Size; + fn sub(self, other: Self) -> Self { + Self { + x: self.x - other.x, + y: self.y - other.y, + } + } +} + +impl From for Size { + fn from(v: RECT) -> Self { + Self { + x: (v.right - v.left) as usize, + y: (v.bottom - v.top) as usize, + } + } +} + +impl From for SIZE { + fn from(v: Size) -> Self { + Self { + cx: v.x as i32, + cy: v.y as i32, + } + } +} + +impl Default for Size { + fn default() -> Self { + Self { x: 0, y: 0 } + } +} + +impl Display for Size { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}x{}", self.x, self.y) + } +} + +fn parse_size(arg: &str) -> Result { + let mut res = arg.split('x'); + + let Some(x) = res.next() else { + return Err(Error::new(ErrorKind::InvalidInput, "Unexpected Input")); + }; + + let Some(y) = res.next() else { + return Err(Error::new(ErrorKind::InvalidInput, "Unexpected Input")); + }; + + let None = res.next() else { + return Err(Error::new(ErrorKind::InvalidInput, "Unexpected Input")); + }; + + Ok(Size { + x: x.parse() + .map_err(|_| Error::new(ErrorKind::InvalidInput, "Unexpected Input"))?, + y: y.parse() + .map_err(|_| Error::new(ErrorKind::InvalidInput, "Unexpected Input"))?, + }) +}