├── .gitignore ├── hh3gf.golden.exe ├── .vscode └── settings.json ├── Cargo.lock ├── LICENSE-APACHE ├── Cargo.toml ├── README.md ├── LICENSE-MIT ├── justfile ├── .cargo └── config.toml └── src └── main.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /hh3gf.golden.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rust9x/rust9x-sample/HEAD/hh3gf.golden.exe -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.cargo.features": "all", 3 | "rust-analyzer.rustfmt.overrideCommand": [ 4 | "rustfmt", 5 | "+nightly" 6 | ] 7 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "rust9x_sample" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Dennis Duda 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust9x_sample" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [features] 9 | default = ["stdin"] 10 | 11 | # Enables the sockaddr and TCP tests, which in turn add a static dependency on WinSock 2 12 | # (ws2_32.dll). This has to be turned off for Windows NT < 4.0, or for Windows 95 without installed 13 | # WinSock 2. 14 | network = [] 15 | stdin = [] 16 | float = [] 17 | 18 | [dependencies] 19 | 20 | [profile.dev] 21 | # Unwind support needs at least VC8 (VS2005) 22 | panic = "unwind" 23 | # panic = "abort" 24 | 25 | [profile.release] 26 | lto = true 27 | codegen-units = 1 28 | debug = 2 29 | # Unwind support needs at least VC8 (VS2005) 30 | panic = "unwind" 31 | # panic = "abort" 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Small test app for various rust9x functionality 2 | 3 | 1. Install `just` (`cargo install just`). 4 | 2. Update the lib paths in `.cargo/config.toml` to match yours. If you want to build for a system 5 | that is already supported natively by your default msvc installation, you can remove these or 6 | comment them out. 7 | 3. Update the variables in the `justfile`. The rust9x toolchain name and `editbin.exe` path (from 8 | your modern msvc build tools) in particular are important. 9 | 4. Use `just build --release` to build using the rust9x toolchain, and regular `cargo` for normal 10 | toolchain builds. 11 | 12 | - Make sure to put `hh3gf.golden.exe` next to the executable for testing. 13 | - If you plan on testing on Windows 9x/ME, make sure to place `unicows.dll` next to the executable 14 | - If you link dynamically, make sure to provide the necessary runtime libraries. 15 | 16 | ## Credits 17 | 18 | `hh3gf.golden.exe` is taken from https://github.com/pts/pts-tinype to test stdout redirection. 19 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2020 Dennis Duda 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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. -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | set shell := ['powershell.exe', '-c'] 2 | 3 | r9x_toolchain := 'rust9x' 4 | r9x_target := 'i586-rust9x-windows-msvc' 5 | r9x_editbin := 'C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Tools\MSVC\14.16.27023\bin\HostX64\x64\editbin.exe' 6 | 7 | # These settings shoud work for Windows 95+ and NT 3.51+. 8 | subsystem := 'CONSOLE,4.0' 9 | os_version := '3.1' 10 | 11 | build *FLAGS: (do-build 'debug' FLAGS) 12 | release *FLAGS: (do-build 'release' '--release' FLAGS) 13 | do-build PROFILE *FLAGS='': (r9x 'build' '--target' r9x_target FLAGS) (editbin 'target\'+r9x_target+'\'+PROFILE+'\rust9x_sample.exe') 14 | run *FLAGS: (r9x 'run' '--target' r9x_target FLAGS) 15 | 16 | r9x $COMMAND *FLAGS: 17 | cargo +{{ r9x_toolchain }} {{ COMMAND }} {{ FLAGS }} 18 | 19 | # PE executables specify the subsystem and subsystem version as well as the required OS version. 20 | # 21 | # `link.exe` has the same switches, but doesn't allow setting them to values that lie outside of the 22 | # supported range of the toolset. `editbin.exe` is a bit more forgiving, only warning about 23 | # "invalid" values (`LINK : warning LNK4241: invalid subsystem version number 4`), but still 24 | # carrying out the change as requested. `/OSVERSION` is entirely undocumented, but still works, 25 | # setting the minimum required OS version. Both values must be in a supported range for the target 26 | # OS to accept and run the executable. 27 | editbin EXECUTABLE: 28 | & "{{ r9x_editbin }}" {{ EXECUTABLE }} /SUBSYSTEM:{{ subsystem }} /OSVERSION:{{ os_version }} /RELEASE /STACK:1048576 29 | -------------------------------------------------------------------------------- /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | 3 | [target.'cfg(target_vendor = "rust9x")'] 4 | rustflags = [ 5 | # Show linker args for debugging purposes 6 | # '--print=link-args', 7 | 8 | # statically linked runtime 9 | '-Ctarget-feature=+crt-static', 10 | # dynamically linked runtime 11 | # '-Ctarget-feature=-crt-static', 12 | 13 | # Add search paths for import libraries 14 | 15 | # VC6: Stdlib doesn't supoprt SAFESEH, panic = "abort" mandatory, unwinding fails 16 | # '-Clink-args=/SAFESEH:NO', 17 | # '-Clink-args=/LIBPATH:X:\rustprojs\rust9x\r9x-buildtools\VS98_SP5\VC98\Lib', 18 | 19 | # VC7.1: Win95 support, panic = "abort" mandatory, unwinding fails 20 | # '-Clink-args=/LIBPATH:X:\rustprojs\rust9x\r9x-buildtools\vc71\Vc7\lib', 21 | # '-Clink-args=/LIBPATH:X:\rustprojs\rust9x\r9x-buildtools\vc71\Vc7\PlatformSDK\Lib', 22 | 23 | # VC8: Win98+ support, panic unwinding works 24 | '-Clink-args=/LIBPATH:X:\rustprojs\rust9x\r9x-buildtools\vc8\VC\lib', 25 | '-Clink-args=/LIBPATH:X:\rustprojs\rust9x\r9x-buildtools\vc8\VC\PlatformSDK\Lib', 26 | 27 | # Any newer version of the toolsets should work just as well! Use e.g. the MSVC2017 XP toolset for 28 | # the most modern XP support. 29 | 30 | # (optional) Disable default libs for full control over linked libraries 31 | # Note that you'll need to add libcmt or msvcrt manually if you disable default libraries 32 | # '-Clink-args=/NODEFAULTLIB', 33 | 34 | # Remove default libs that unicows wraps/overrides 35 | '-Clink-args=/nod:kernel32.lib /nod:advapi32.lib /nod:user32.lib /nod:gdi32.lib /nod:shell32.lib /nod:comdlg32.lib /nod:version.lib /nod:mpr.lib /nod:rasapi32.lib /nod:winmm.lib /nod:winspool.lib /nod:vfw32.lib /nod:secur32.lib /nod:oleacc.lib /nod:oledlg.lib /nod:sensapi.lib', 36 | 37 | # Then link unicows itself, allowing the linker to resolve symbols to it instead of the wrapped 38 | # libraries 39 | '-Clink-arg=unicows.lib', 40 | 41 | # Then add back the default libs that were removed 42 | '-Clink-args=kernel32.lib advapi32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib version.lib mpr.lib rasapi32.lib winmm.lib winspool.lib vfw32.lib secur32.lib oleacc.lib oledlg.lib sensapi.lib', 43 | 44 | # Add modern universal CRT for missing float/math intrinsics. see `cfg(feature = "float")` in 45 | # `main.rs` 46 | # '-Clink-args=libucrt.lib', 47 | ] 48 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::backtrace::Backtrace; 2 | use std::cell::RefCell; 3 | #[cfg(feature = "network")] 4 | use std::io::Read; 5 | use std::io::{stdout, Seek, SeekFrom, Write}; 6 | #[cfg(feature = "network")] 7 | use std::net::{TcpListener, ToSocketAddrs}; 8 | use std::os::windows::fs::FileExt; 9 | use std::process::Command; 10 | use std::sync::{Arc, Condvar, Mutex, RwLock}; 11 | use std::thread; 12 | use std::time::{Duration, SystemTime}; 13 | 14 | /// This needs to be set for libucrt to be able to do "dynamic" dispatch to optimized float 15 | /// intrinsics. We just hardcode it to 0 here - feel free to implement CPUID detection and set it to 16 | /// one of the following values: 17 | /// 18 | /// __ISA_AVAILABLE_X86 equ 0 19 | /// __ISA_AVAILABLE_SSE2 equ 1 20 | /// __ISA_AVAILABLE_SSE42 equ 2 21 | /// __ISA_AVAILABLE_AVX equ 3 22 | #[cfg(feature = "float")] 23 | #[unsafe(no_mangle)] 24 | #[used] 25 | #[allow(non_upper_case_globals)] 26 | pub static __isa_available: std::ffi::c_int = 0; 27 | 28 | fn main() { 29 | test_stdout(); 30 | test_thread_locals(); 31 | test_mutex(); 32 | test_rwlock(); 33 | test_condvar(); 34 | 35 | test_panic_unwind(); 36 | test_backtrace(); 37 | 38 | test_time_and_sleep(); 39 | test_home_dir(); 40 | test_hashset_random_init(); 41 | 42 | test_file_seek_truncate_append_fileext(); 43 | test_readdir(); 44 | test_delete_dir_all(); 45 | 46 | test_process_stdio_redirect(); 47 | 48 | #[cfg(feature = "float")] 49 | { 50 | test_float_intrinsics(); 51 | } 52 | 53 | #[cfg(feature = "stdin")] 54 | { 55 | test_stdin(); 56 | } 57 | 58 | #[cfg(feature = "network")] 59 | { 60 | test_sockaddr(); 61 | test_tcp(); 62 | } 63 | } 64 | 65 | #[inline(never)] 66 | fn test_readdir() { 67 | println!("Reading current directory:"); 68 | for entry in std::fs::read_dir(".").unwrap().flatten() { 69 | println!(" - {}", entry.path().display()); 70 | } 71 | } 72 | 73 | #[inline(never)] 74 | fn test_delete_dir_all() { 75 | let base_folder = r".\_r9xtmp"; 76 | let folder = &format!(r"{base_folder}\a\b\c"); 77 | std::fs::create_dir_all(folder).unwrap(); 78 | 79 | let mut file = std::fs::OpenOptions::new() 80 | .write(true) 81 | .create_new(true) 82 | .open(format!(r"{folder}\rust9x.txt")) 83 | .unwrap(); 84 | file.write_all(b"Hello world!").unwrap(); 85 | file.flush().unwrap(); 86 | drop(file); 87 | 88 | std::thread::sleep(Duration::from_millis(500)); 89 | 90 | std::fs::remove_dir_all(base_folder).unwrap(); 91 | assert!(!std::fs::exists(base_folder).unwrap()); 92 | } 93 | 94 | #[inline(never)] 95 | fn test_stdout() { 96 | println!("Testing UTF-8 console stdout fallback: ÄÖÜß, 你好,世界 🦀🦀"); 97 | } 98 | 99 | #[cfg(feature = "stdin")] 100 | #[inline(never)] 101 | fn test_stdin() { 102 | println!("input some string, enter to continue"); 103 | let mut buffer = String::new(); 104 | std::io::stdin().read_line(&mut buffer).unwrap(); 105 | println!("{}", buffer); 106 | } 107 | 108 | #[inline(never)] 109 | fn test_home_dir() { 110 | #[allow(deprecated)] 111 | let home_dir = std::env::home_dir(); 112 | println!("Home dir: {:?}", home_dir.as_ref().map(|p| p.display())); 113 | } 114 | 115 | #[inline(never)] 116 | fn test_hashset_random_init() { 117 | let mut set = std::collections::HashSet::with_capacity(16); 118 | for i in 0..16 { 119 | set.insert(i); 120 | } 121 | 122 | print!("Hashset:"); 123 | for i in set { 124 | print!(" {}", i); 125 | } 126 | println!(); 127 | } 128 | 129 | #[inline(never)] 130 | fn test_time_and_sleep() { 131 | let now = SystemTime::now(); 132 | println!("System time: {now:?}"); 133 | match now.duration_since(SystemTime::UNIX_EPOCH) { 134 | Ok(d) => println!(" Duration since unix epoch: {}s", d.as_secs()), 135 | Err(_) => println!(" Duration since unix epoch: Error: SystemTime before UNIX EPOCH!"), 136 | } 137 | println!("Testing sleep"); 138 | thread::sleep(Duration::from_millis(10)); 139 | thread::yield_now(); 140 | let now = SystemTime::now(); 141 | println!("System time: {now:?}"); 142 | } 143 | 144 | #[cfg(feature = "float")] 145 | #[inline(never)] 146 | fn test_float_intrinsics() { 147 | let a: f64 = 0.75; 148 | println!("1: {}, 0: {}", a.round(), a.trunc()); 149 | } 150 | 151 | #[inline(never)] 152 | fn test_backtrace() { 153 | let backtrace = Backtrace::capture(); 154 | println!("Testing backtrace, might need RUST_BACKTRACE=1 or =full:\n{backtrace}"); 155 | } 156 | 157 | #[inline(never)] 158 | fn test_file_seek_truncate_append_fileext() { 159 | let mut file = std::fs::OpenOptions::new() 160 | .write(true) 161 | .create(true) 162 | .truncate(true) 163 | .open("rust9x.txt") 164 | .unwrap(); 165 | 166 | file.write_all(b"Hello world!").unwrap(); 167 | file.seek(SeekFrom::Start(0)).unwrap(); 168 | file.write_all(b"bye ").unwrap(); 169 | file.set_len(9).unwrap(); 170 | file.flush().unwrap(); 171 | drop(file); 172 | 173 | let s = std::fs::read_to_string("rust9x.txt").unwrap(); 174 | 175 | println!("File after write/seek/set_len: {:?}", s); 176 | assert_eq!(&s, "bye wor"); 177 | 178 | let mut file = std::fs::OpenOptions::new() 179 | .write(true) 180 | .open("rust9x.txt") 181 | .unwrap(); 182 | 183 | // just assuming that the whole buffer gets written in this case 184 | file.seek_write(b"Hello", 0).unwrap(); 185 | file.flush().unwrap(); 186 | drop(file); 187 | 188 | let mut file = std::fs::OpenOptions::new() 189 | .append(true) 190 | .open("rust9x.txt") 191 | .unwrap(); 192 | 193 | file.write_all(b"ld!").unwrap(); 194 | file.flush().unwrap(); 195 | drop(file); 196 | 197 | let s = std::fs::read_to_string("rust9x.txt").unwrap(); 198 | 199 | println!("File after seek_write/append: {:?}", s); 200 | assert_eq!(&s, "Hello world!"); 201 | 202 | std::fs::remove_file("rust9x.txt").unwrap(); 203 | } 204 | 205 | struct ThreadLocalPrintOnDrop { 206 | val: u32, 207 | } 208 | 209 | impl Drop for ThreadLocalPrintOnDrop { 210 | fn drop(&mut self) { 211 | println!("Thread local dropped, value: {}", self.val); 212 | } 213 | } 214 | 215 | thread_local! { 216 | #[allow(clippy::missing_const_for_thread_local)] 217 | static FOO: RefCell = 218 | RefCell::new(ThreadLocalPrintOnDrop { val: 0 }); 219 | } 220 | 221 | #[inline(never)] 222 | fn test_thread_locals() { 223 | let i = thread::spawn(|| { 224 | FOO.with(|n| n.borrow_mut().val = 42); 225 | println!( 226 | "set one thread's local to be 42, ending that thread now. It should print the value..." 227 | ); 228 | }); 229 | 230 | i.join().unwrap(); 231 | } 232 | 233 | #[inline(never)] 234 | fn test_process_stdio_redirect() { 235 | println!(r"Running `hh3gf.golden.exe`, should print `Hello, World!\r\n`"); 236 | let output = Command::new("./hh3gf.golden.exe") 237 | .stdout(std::process::Stdio::piped()) 238 | .stderr(std::process::Stdio::piped()) 239 | .output() 240 | .unwrap(); 241 | 242 | if let Ok(s) = std::str::from_utf8(&output.stdout) { 243 | println!(" Redirected stdout: {}", s); 244 | println!(" Redirected stderr len: {}", output.stderr.len()); 245 | assert_eq!(s, "Hello, World!\r\n"); 246 | } else { 247 | panic!("Output was not valid utf8"); 248 | } 249 | } 250 | 251 | #[inline(never)] 252 | fn test_mutex() { 253 | let m = Arc::new(Mutex::new(5usize)); 254 | 255 | let mut map = std::collections::HashMap::with_capacity(16); 256 | 257 | let mut num_guard = m.lock().unwrap(); 258 | *num_guard = 0; 259 | 260 | { 261 | let mut l = stdout().lock(); 262 | write!(l, "Mutex: ").unwrap(); 263 | l.flush().unwrap(); 264 | } 265 | 266 | for n in 0usize..16 { 267 | let m = m.clone(); 268 | map.insert( 269 | n, 270 | thread::spawn(move || { 271 | thread::sleep(Duration::from_millis((n * 100) as u64)); 272 | loop { 273 | let mut num_guard = m.lock().unwrap(); 274 | 275 | if *num_guard == n { 276 | *num_guard += 1; 277 | break; 278 | } 279 | 280 | drop(num_guard); 281 | 282 | thread::sleep(Duration::from_millis(100)) 283 | } 284 | }), 285 | ); 286 | } 287 | 288 | drop(num_guard); 289 | 290 | for (_, v) in map { 291 | v.join().unwrap(); 292 | } 293 | 294 | println!("done ({:?})", *m.lock().unwrap()); 295 | } 296 | 297 | #[inline(never)] 298 | fn test_rwlock() { 299 | let m = Arc::new(RwLock::new(5usize)); 300 | 301 | let mut map = std::collections::HashMap::with_capacity(16); 302 | 303 | let mut num_guard = m.write().unwrap(); 304 | *num_guard = 0; 305 | 306 | { 307 | let mut l = stdout().lock(); 308 | write!(l, "RwLock:").unwrap(); 309 | l.flush().unwrap(); 310 | } 311 | 312 | for n in 0usize..16 { 313 | let m = m.clone(); 314 | map.insert( 315 | n, 316 | thread::spawn(move || { 317 | thread::sleep(Duration::from_millis((n * 100) as u64)); 318 | let mut num_guard = m.write().unwrap(); 319 | 320 | *num_guard += 1; 321 | 322 | drop(num_guard); 323 | }), 324 | ); 325 | } 326 | 327 | { 328 | let m = m.clone(); 329 | thread::spawn(move || loop { 330 | let read = m.read().unwrap(); 331 | 332 | if *read == 16 { 333 | return; 334 | } 335 | 336 | { 337 | let mut l = stdout().lock(); 338 | write!(l, " {read}").unwrap(); 339 | l.flush().unwrap(); 340 | } 341 | 342 | drop(read); 343 | 344 | thread::sleep(Duration::from_millis(50)); 345 | }); 346 | } 347 | 348 | drop(num_guard); 349 | 350 | for (_, v) in map { 351 | v.join().unwrap(); 352 | } 353 | 354 | println!(" done ({:?})", *m.read().unwrap()); 355 | } 356 | 357 | #[inline(never)] 358 | fn test_condvar() { 359 | let pair = Arc::new((Mutex::new(false), Condvar::new())); 360 | 361 | println!("Condvar: starting threads"); 362 | let mut threads = Vec::with_capacity(16); 363 | for n in 0usize..16 { 364 | let pair = pair.clone(); 365 | threads.push(thread::spawn(move || { 366 | let (lock, cvar) = &*pair; 367 | let mut guard = lock.lock().unwrap(); 368 | while !*guard { 369 | guard = cvar.wait(guard).unwrap(); 370 | } 371 | println!(" {:2} woke up", n); 372 | })); 373 | } 374 | 375 | thread::sleep(Duration::from_millis(100)); 376 | println!(" causing a spurious wakeup..."); 377 | pair.1.notify_all(); 378 | 379 | thread::sleep(Duration::from_millis(100)); 380 | println!(" proper wakeup..."); 381 | *pair.0.lock().unwrap() = true; 382 | pair.1.notify_all(); 383 | 384 | for t in threads { 385 | t.join().unwrap(); 386 | } 387 | } 388 | 389 | #[cfg(feature = "network")] 390 | #[inline(never)] 391 | fn test_sockaddr() { 392 | println!("Socket addr check for google.com:80:",); 393 | for addr in ("google.com", 80u16).to_socket_addrs().unwrap() { 394 | println!(" {:?}", addr); 395 | } 396 | } 397 | 398 | #[cfg(feature = "network")] 399 | #[inline(never)] 400 | fn test_tcp() { 401 | println!("Tcp: starting server at 0.0.0.0:40004, CTRL+C to exit"); 402 | let listener = TcpListener::bind("0.0.0.0:40004").unwrap(); 403 | 404 | let mut v = Vec::with_capacity(1024); 405 | 406 | loop { 407 | v.clear(); 408 | 409 | let (mut stream, addr) = listener.accept().unwrap(); 410 | println!(" connection from {addr:?}"); 411 | let mut buf = [0u8; 1024]; 412 | 413 | loop { 414 | let n = stream.read(&mut buf).unwrap(); 415 | if n == 0 { 416 | break; 417 | } 418 | v.extend_from_slice(&buf[..n]); 419 | if v.windows(4).any(|w| w == b"\r\n\r\n") { 420 | break; 421 | } 422 | } 423 | 424 | if v.starts_with(b"GET /") { 425 | stream 426 | .write_all( 427 | b"HTTP/1.1 200 OK\r\n\ 428 | Server: rust9x\r\n\ 429 | Content-Length: 38\r\n\ 430 | Content-Type: text/html\r\n\ 431 | Connection: Closed\r\n\r\n\ 432 | Hello World!", 433 | ) 434 | .unwrap(); 435 | stream.flush().unwrap(); 436 | } 437 | 438 | let _ = stream.shutdown(std::net::Shutdown::Both); 439 | drop(stream); 440 | } 441 | } 442 | 443 | #[cfg(panic = "abort")] 444 | #[inline(never)] 445 | fn test_panic_unwind() { 446 | // can't test unwinding without unwind 447 | } 448 | 449 | #[cfg(panic = "unwind")] 450 | #[inline(never)] 451 | fn test_panic_unwind() { 452 | fn inner() { 453 | panic!("woop"); 454 | } 455 | 456 | println!("Testing catch_unwind"); 457 | if std::panic::catch_unwind(inner).is_err() { 458 | println!(" unwind caught panic successfully"); 459 | } else { 460 | // if the panic *wasn't* caught we wouldn't get here anyways 461 | unreachable!(); 462 | } 463 | } 464 | --------------------------------------------------------------------------------