├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile.toml ├── README.md ├── flyweight ├── big0.txt ├── big1.txt ├── big2.txt ├── big3.txt ├── big4.txt ├── big5.txt ├── big6.txt ├── big7.txt ├── big8.txt └── big9.txt ├── renovate.json ├── rust-toolchain.toml ├── rustfmt.toml └── src ├── adaptor.rs ├── adaptor ├── enum_base.rs └── trait_base.rs ├── bridge.rs ├── bridge ├── enum_base.rs ├── generic_base.rs └── trait_base.rs ├── builder.rs ├── chain_of_responsibility.rs ├── chain_of_responsibility ├── enum_base.rs └── trait_base.rs ├── command.rs ├── command ├── enum_base.rs ├── generic_base.rs └── trait_base.rs ├── composite.rs ├── composite ├── enum_base.rs ├── generic_base.rs └── trait_base.rs ├── decorator.rs ├── decorator ├── enum_base.rs └── trait_base.rs ├── factory_method.rs ├── flyweight.rs ├── iterator.rs ├── main.rs ├── mediator.rs ├── observer.rs ├── observer ├── enum_base.rs └── trait_base.rs ├── proxy.rs ├── proxy ├── enum_base.rs └── trait_base.rs ├── singleton.rs ├── state.rs ├── state ├── enum_base.rs └── trait_base.rs ├── strategy.rs ├── strategy ├── enum_base.rs └── trait_base.rs ├── template_method_new.rs ├── template_method_old.rs ├── visitor.rs └── visitor ├── enum_base.rs └── trait_base.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea/ 3 | .DS_Store -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "android-tzdata" 7 | version = "0.1.1" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 10 | 11 | [[package]] 12 | name = "android_system_properties" 13 | version = "0.1.5" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 16 | dependencies = [ 17 | "libc", 18 | ] 19 | 20 | [[package]] 21 | name = "anyhow" 22 | version = "1.0.98" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" 25 | 26 | [[package]] 27 | name = "autocfg" 28 | version = "1.1.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 31 | 32 | [[package]] 33 | name = "bitflags" 34 | version = "2.8.0" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 37 | 38 | [[package]] 39 | name = "bumpalo" 40 | version = "3.10.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" 43 | 44 | [[package]] 45 | name = "cc" 46 | version = "1.0.79" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" 49 | 50 | [[package]] 51 | name = "cfg-if" 52 | version = "1.0.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 55 | 56 | [[package]] 57 | name = "chrono" 58 | version = "0.4.41" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" 61 | dependencies = [ 62 | "android-tzdata", 63 | "iana-time-zone", 64 | "js-sys", 65 | "num-traits", 66 | "wasm-bindgen", 67 | "windows-link", 68 | ] 69 | 70 | [[package]] 71 | name = "codespan-reporting" 72 | version = "0.11.1" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" 75 | dependencies = [ 76 | "termcolor", 77 | "unicode-width", 78 | ] 79 | 80 | [[package]] 81 | name = "core-foundation-sys" 82 | version = "0.8.3" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" 85 | 86 | [[package]] 87 | name = "cxx" 88 | version = "1.0.92" 89 | source = "registry+https://github.com/rust-lang/crates.io-index" 90 | checksum = "9a140f260e6f3f79013b8bfc65e7ce630c9ab4388c6a89c71e07226f49487b72" 91 | dependencies = [ 92 | "cc", 93 | "cxxbridge-flags", 94 | "cxxbridge-macro", 95 | "link-cplusplus", 96 | ] 97 | 98 | [[package]] 99 | name = "cxx-build" 100 | version = "1.0.92" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "da6383f459341ea689374bf0a42979739dc421874f112ff26f829b8040b8e613" 103 | dependencies = [ 104 | "cc", 105 | "codespan-reporting", 106 | "once_cell", 107 | "proc-macro2", 108 | "quote", 109 | "scratch", 110 | "syn 1.0.99", 111 | ] 112 | 113 | [[package]] 114 | name = "cxxbridge-flags" 115 | version = "1.0.92" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "90201c1a650e95ccff1c8c0bb5a343213bdd317c6e600a93075bca2eff54ec97" 118 | 119 | [[package]] 120 | name = "cxxbridge-macro" 121 | version = "1.0.92" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "0b75aed41bb2e6367cae39e6326ef817a851db13c13e4f3263714ca3cfb8de56" 124 | dependencies = [ 125 | "proc-macro2", 126 | "quote", 127 | "syn 1.0.99", 128 | ] 129 | 130 | [[package]] 131 | name = "design-patterns-in-rust" 132 | version = "0.1.0" 133 | dependencies = [ 134 | "anyhow", 135 | "chrono", 136 | "once_cell", 137 | "rand", 138 | "timer", 139 | ] 140 | 141 | [[package]] 142 | name = "getrandom" 143 | version = "0.3.0" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "71393ecc86efbf00e4ca13953979ba8b94cfe549a4b74cc26d8b62f4d8feac2b" 146 | dependencies = [ 147 | "cfg-if", 148 | "libc", 149 | "wasi", 150 | "windows-targets", 151 | ] 152 | 153 | [[package]] 154 | name = "iana-time-zone" 155 | version = "0.1.53" 156 | source = "registry+https://github.com/rust-lang/crates.io-index" 157 | checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" 158 | dependencies = [ 159 | "android_system_properties", 160 | "core-foundation-sys", 161 | "iana-time-zone-haiku", 162 | "js-sys", 163 | "wasm-bindgen", 164 | "winapi", 165 | ] 166 | 167 | [[package]] 168 | name = "iana-time-zone-haiku" 169 | version = "0.1.1" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" 172 | dependencies = [ 173 | "cxx", 174 | "cxx-build", 175 | ] 176 | 177 | [[package]] 178 | name = "js-sys" 179 | version = "0.3.59" 180 | source = "registry+https://github.com/rust-lang/crates.io-index" 181 | checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" 182 | dependencies = [ 183 | "wasm-bindgen", 184 | ] 185 | 186 | [[package]] 187 | name = "libc" 188 | version = "0.2.169" 189 | source = "registry+https://github.com/rust-lang/crates.io-index" 190 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 191 | 192 | [[package]] 193 | name = "link-cplusplus" 194 | version = "1.0.8" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" 197 | dependencies = [ 198 | "cc", 199 | ] 200 | 201 | [[package]] 202 | name = "log" 203 | version = "0.4.17" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 206 | dependencies = [ 207 | "cfg-if", 208 | ] 209 | 210 | [[package]] 211 | name = "num-traits" 212 | version = "0.2.14" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 215 | dependencies = [ 216 | "autocfg", 217 | ] 218 | 219 | [[package]] 220 | name = "once_cell" 221 | version = "1.21.3" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 224 | 225 | [[package]] 226 | name = "ppv-lite86" 227 | version = "0.2.16" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" 230 | 231 | [[package]] 232 | name = "proc-macro2" 233 | version = "1.0.93" 234 | source = "registry+https://github.com/rust-lang/crates.io-index" 235 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 236 | dependencies = [ 237 | "unicode-ident", 238 | ] 239 | 240 | [[package]] 241 | name = "quote" 242 | version = "1.0.38" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 245 | dependencies = [ 246 | "proc-macro2", 247 | ] 248 | 249 | [[package]] 250 | name = "rand" 251 | version = "0.9.1" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" 254 | dependencies = [ 255 | "rand_chacha", 256 | "rand_core", 257 | ] 258 | 259 | [[package]] 260 | name = "rand_chacha" 261 | version = "0.9.0" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 264 | dependencies = [ 265 | "ppv-lite86", 266 | "rand_core", 267 | ] 268 | 269 | [[package]] 270 | name = "rand_core" 271 | version = "0.9.0" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" 274 | dependencies = [ 275 | "getrandom", 276 | "zerocopy", 277 | ] 278 | 279 | [[package]] 280 | name = "scratch" 281 | version = "1.0.5" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" 284 | 285 | [[package]] 286 | name = "syn" 287 | version = "1.0.99" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" 290 | dependencies = [ 291 | "proc-macro2", 292 | "quote", 293 | "unicode-ident", 294 | ] 295 | 296 | [[package]] 297 | name = "syn" 298 | version = "2.0.96" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" 301 | dependencies = [ 302 | "proc-macro2", 303 | "quote", 304 | "unicode-ident", 305 | ] 306 | 307 | [[package]] 308 | name = "termcolor" 309 | version = "1.2.0" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" 312 | dependencies = [ 313 | "winapi-util", 314 | ] 315 | 316 | [[package]] 317 | name = "timer" 318 | version = "0.2.0" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b" 321 | dependencies = [ 322 | "chrono", 323 | ] 324 | 325 | [[package]] 326 | name = "unicode-ident" 327 | version = "1.0.3" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" 330 | 331 | [[package]] 332 | name = "unicode-width" 333 | version = "0.1.10" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" 336 | 337 | [[package]] 338 | name = "wasi" 339 | version = "0.13.3+wasi-0.2.2" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" 342 | dependencies = [ 343 | "wit-bindgen-rt", 344 | ] 345 | 346 | [[package]] 347 | name = "wasm-bindgen" 348 | version = "0.2.82" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" 351 | dependencies = [ 352 | "cfg-if", 353 | "wasm-bindgen-macro", 354 | ] 355 | 356 | [[package]] 357 | name = "wasm-bindgen-backend" 358 | version = "0.2.82" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" 361 | dependencies = [ 362 | "bumpalo", 363 | "log", 364 | "once_cell", 365 | "proc-macro2", 366 | "quote", 367 | "syn 1.0.99", 368 | "wasm-bindgen-shared", 369 | ] 370 | 371 | [[package]] 372 | name = "wasm-bindgen-macro" 373 | version = "0.2.82" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" 376 | dependencies = [ 377 | "quote", 378 | "wasm-bindgen-macro-support", 379 | ] 380 | 381 | [[package]] 382 | name = "wasm-bindgen-macro-support" 383 | version = "0.2.82" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" 386 | dependencies = [ 387 | "proc-macro2", 388 | "quote", 389 | "syn 1.0.99", 390 | "wasm-bindgen-backend", 391 | "wasm-bindgen-shared", 392 | ] 393 | 394 | [[package]] 395 | name = "wasm-bindgen-shared" 396 | version = "0.2.82" 397 | source = "registry+https://github.com/rust-lang/crates.io-index" 398 | checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" 399 | 400 | [[package]] 401 | name = "winapi" 402 | version = "0.3.9" 403 | source = "registry+https://github.com/rust-lang/crates.io-index" 404 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 405 | dependencies = [ 406 | "winapi-i686-pc-windows-gnu", 407 | "winapi-x86_64-pc-windows-gnu", 408 | ] 409 | 410 | [[package]] 411 | name = "winapi-i686-pc-windows-gnu" 412 | version = "0.4.0" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 415 | 416 | [[package]] 417 | name = "winapi-util" 418 | version = "0.1.5" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 421 | dependencies = [ 422 | "winapi", 423 | ] 424 | 425 | [[package]] 426 | name = "winapi-x86_64-pc-windows-gnu" 427 | version = "0.4.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 430 | 431 | [[package]] 432 | name = "windows-link" 433 | version = "0.1.0" 434 | source = "registry+https://github.com/rust-lang/crates.io-index" 435 | checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" 436 | 437 | [[package]] 438 | name = "windows-targets" 439 | version = "0.52.0" 440 | source = "registry+https://github.com/rust-lang/crates.io-index" 441 | checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" 442 | dependencies = [ 443 | "windows_aarch64_gnullvm", 444 | "windows_aarch64_msvc", 445 | "windows_i686_gnu", 446 | "windows_i686_msvc", 447 | "windows_x86_64_gnu", 448 | "windows_x86_64_gnullvm", 449 | "windows_x86_64_msvc", 450 | ] 451 | 452 | [[package]] 453 | name = "windows_aarch64_gnullvm" 454 | version = "0.52.0" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" 457 | 458 | [[package]] 459 | name = "windows_aarch64_msvc" 460 | version = "0.52.0" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" 463 | 464 | [[package]] 465 | name = "windows_i686_gnu" 466 | version = "0.52.0" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" 469 | 470 | [[package]] 471 | name = "windows_i686_msvc" 472 | version = "0.52.0" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" 475 | 476 | [[package]] 477 | name = "windows_x86_64_gnu" 478 | version = "0.52.0" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" 481 | 482 | [[package]] 483 | name = "windows_x86_64_gnullvm" 484 | version = "0.52.0" 485 | source = "registry+https://github.com/rust-lang/crates.io-index" 486 | checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" 487 | 488 | [[package]] 489 | name = "windows_x86_64_msvc" 490 | version = "0.52.0" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" 493 | 494 | [[package]] 495 | name = "wit-bindgen-rt" 496 | version = "0.33.0" 497 | source = "registry+https://github.com/rust-lang/crates.io-index" 498 | checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" 499 | dependencies = [ 500 | "bitflags", 501 | ] 502 | 503 | [[package]] 504 | name = "zerocopy" 505 | version = "0.8.14" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "a367f292d93d4eab890745e75a778da40909cab4d6ff8173693812f79c4a2468" 508 | dependencies = [ 509 | "zerocopy-derive", 510 | ] 511 | 512 | [[package]] 513 | name = "zerocopy-derive" 514 | version = "0.8.14" 515 | source = "registry+https://github.com/rust-lang/crates.io-index" 516 | checksum = "d3931cb58c62c13adec22e38686b559c86a30565e16ad6e8510a337cedc611e1" 517 | dependencies = [ 518 | "proc-macro2", 519 | "quote", 520 | "syn 2.0.96", 521 | ] 522 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "design-patterns-in-rust" 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 | [dependencies] 9 | anyhow = "1.0.82" 10 | once_cell = "1.19.0" 11 | rand = "0.9.0" 12 | chrono = "0.4.38" 13 | timer = "0.2.0" 14 | 15 | [dev-dependencies] 16 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [2020] Junichi Kato 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Junichi Kato 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [tasks.fmt] 2 | description = "Format source code" 3 | workspace = false 4 | install_script = [''' 5 | #!/usr/bin/env bash 6 | rustup which rustfmt --toolchain nightly 7 | if [ $? -ne 0 ]; then 8 | rustup install nightly 9 | fi 10 | '''] 11 | script = ''' 12 | #!/usr/bin/env bash 13 | cargo +nightly fmt 14 | ''' 15 | 16 | [tasks.sort-dependencies] 17 | workspace = false 18 | script_runner = "@rust" 19 | script = ''' 20 | //! ```cargo 21 | //! [dependencies] 22 | //! toml_edit = "0.22.0" 23 | //! ``` 24 | use std::fs; 25 | use std::path::Path; 26 | use toml_edit::{Document, Item, Table, InlineTable}; 27 | 28 | fn main() -> Result<(), Box> { 29 | let cargo_toml_paths = [ 30 | "Cargo.toml", 31 | "utils/Cargo.toml", 32 | "message-derive/Cargo.toml", 33 | "core/Cargo.toml", 34 | "remote/Cargo.toml", 35 | "cluster/Cargo.toml", 36 | ]; 37 | 38 | for path in cargo_toml_paths.iter() { 39 | let path = Path::new(path); 40 | if path.exists() { 41 | backup_cargo_toml(path)?; 42 | sort_dependencies(path)?; 43 | } else { 44 | println!("Warning: {} not found", path.display()); 45 | } 46 | } 47 | 48 | Ok(()) 49 | } 50 | 51 | // Create a backup of Cargo.toml -> Cargo.toml.bak 52 | fn backup_cargo_toml(file_path: &Path) -> Result<(), Box> { 53 | let backup_path = file_path.with_extension("toml.bak"); 54 | fs::copy(file_path, &backup_path)?; 55 | println!("Backup created: {}", backup_path.display()); 56 | Ok(()) 57 | } 58 | 59 | fn sort_table(table: &mut Table) { 60 | let mut keys: Vec<_> = table.iter().map(|(k, _)| k.to_string()).collect(); 61 | keys.sort(); 62 | 63 | let sorted_table = keys.into_iter() 64 | .filter_map(|k| table.get(&k).map(|v| (k, v.clone()))) 65 | .collect(); 66 | 67 | *table = sorted_table; 68 | } 69 | 70 | fn sort_inline_table(table: &mut InlineTable) { 71 | let mut keys: Vec<_> = table.iter().map(|(k, _)| k.to_string()).collect(); 72 | keys.sort(); 73 | 74 | let sorted_table = keys.into_iter() 75 | .filter_map(|k| table.get(&k).map(|v| (k, v.clone()))) 76 | .collect(); 77 | 78 | *table = sorted_table; 79 | } 80 | 81 | fn sort_dependencies(file_path: &Path) -> Result<(), Box> { 82 | let content = fs::read_to_string(file_path)?; 83 | let mut doc = content.parse::()?; 84 | 85 | // Sort workspace dependencies 86 | if let Some(workspace) = doc.get_mut("workspace") { 87 | if let Some(deps) = workspace.get_mut("dependencies") { 88 | match deps { 89 | Item::Table(table) => { 90 | sort_table(table); 91 | println!("Sorted workspace.dependencies in {}", file_path.display()); 92 | }, 93 | Item::Value(value) => { 94 | if let Some(inline_table) = value.as_inline_table_mut() { 95 | sort_inline_table(inline_table); 96 | println!("Sorted workspace.dependencies in {}", file_path.display()); 97 | } 98 | }, 99 | _ => {} 100 | } 101 | } 102 | } 103 | 104 | // Sort other dependency sections 105 | let sections = ["dependencies", "dev-dependencies", "build-dependencies"]; 106 | 107 | for section in sections.iter() { 108 | if let Some(deps) = doc.get_mut(section) { 109 | match deps { 110 | Item::Table(table) => { 111 | sort_table(table); 112 | println!("Sorted {} in {}", section, file_path.display()); 113 | }, 114 | Item::Value(value) => { 115 | if let Some(inline_table) = value.as_inline_table_mut() { 116 | sort_inline_table(inline_table); 117 | println!("Sorted {} in {}", section, file_path.display()); 118 | } 119 | }, 120 | _ => {} 121 | } 122 | } 123 | } 124 | 125 | fs::write(file_path, doc.to_string())?; 126 | println!("Updated {} successfully", file_path.display()); 127 | 128 | Ok(()) 129 | } 130 | ''' 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoFデザインパターンをRustで実装した例 2 | 3 | 絶賛実装中です… 4 | 5 | 元ネタは [Java言語で学ぶデザインパターン入門第3版](https://amzn.to/36y0lWx) です。 6 | 7 | https://www.hyuki.com/dp/ からソースコードをダウンロードできます。 8 | 9 | 要は、Javaで書かれたコードをRustに書き換えます。Javaの実装コードはイメージできるけど、Rustではイメージできないという方向けのコンテンツです。 10 | 11 | いまどきsetter書かせやがってとコードをみたとき思いましたが、一旦そのままRust版として実装しています。 -------------------------------------------------------------------------------- /flyweight/big0.txt: -------------------------------------------------------------------------------- 1 | ....######...... 2 | ..##......##.... 3 | ..##......##.... 4 | ..##......##.... 5 | ..##......##.... 6 | ..##......##.... 7 | ....######...... 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big1.txt: -------------------------------------------------------------------------------- 1 | ......##........ 2 | ..######........ 3 | ......##........ 4 | ......##........ 5 | ......##........ 6 | ......##........ 7 | ..##########.... 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big2.txt: -------------------------------------------------------------------------------- 1 | ....######...... 2 | ..##......##.... 3 | ..........##.... 4 | ......####...... 5 | ....##.......... 6 | ..##............ 7 | ..##########.... 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big3.txt: -------------------------------------------------------------------------------- 1 | ....######...... 2 | ..##......##.... 3 | ..........##.... 4 | ......####...... 5 | ..........##.... 6 | ..##......##.... 7 | ....######...... 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big4.txt: -------------------------------------------------------------------------------- 1 | ........##...... 2 | ......####...... 3 | ....##..##...... 4 | ..##....##...... 5 | ..##########.... 6 | ........##...... 7 | ......######.... 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big5.txt: -------------------------------------------------------------------------------- 1 | ..##########.... 2 | ..##............ 3 | ..##............ 4 | ..########...... 5 | ..........##.... 6 | ..##......##.... 7 | ....######...... 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big6.txt: -------------------------------------------------------------------------------- 1 | ....######...... 2 | ..##......##.... 3 | ..##............ 4 | ..########...... 5 | ..##......##.... 6 | ..##......##.... 7 | ....######...... 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big7.txt: -------------------------------------------------------------------------------- 1 | ..##########.... 2 | ..##......##.... 3 | ..........##.... 4 | ........##...... 5 | ......##........ 6 | ......##........ 7 | ......##........ 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big8.txt: -------------------------------------------------------------------------------- 1 | ....######...... 2 | ..##......##.... 3 | ..##......##.... 4 | ....######...... 5 | ..##......##.... 6 | ..##......##.... 7 | ....######...... 8 | ................ 9 | -------------------------------------------------------------------------------- /flyweight/big9.txt: -------------------------------------------------------------------------------- 1 | ....######...... 2 | ..##......##.... 3 | ..##......##.... 4 | ....########.... 5 | ..........##.... 6 | ..##......##.... 7 | ....######...... 8 | ................ 9 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "cargo": { 6 | "enabled": true 7 | }, 8 | "platformAutomerge": true, 9 | "packageRules": [ 10 | { 11 | "matchUpdateTypes": [ 12 | "minor", 13 | "patch", 14 | "pin", 15 | "digest" 16 | ], 17 | "automerge": true 18 | }, 19 | { 20 | "matchDepTypes": [ 21 | "devDependencies" 22 | ], 23 | "automerge": true 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" 3 | components = ["rustfmt", "clippy"] -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 120 2 | newline_style = "Unix" 3 | indent_style = "Block" 4 | normalize_comments = true 5 | brace_style = "PreferSameLine" 6 | reorder_imports = true 7 | reorder_impl_items = true 8 | reorder_modules = true 9 | tab_spaces = 2 -------------------------------------------------------------------------------- /src/adaptor.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod trait_base; 3 | 4 | #[derive(Debug)] 5 | pub struct Banner(String); 6 | 7 | impl Banner { 8 | pub fn new(s: &str) -> Self { 9 | Self(s.to_owned()) 10 | } 11 | 12 | pub fn show_with_paren(&self) { 13 | println!("({})", self.0); 14 | } 15 | 16 | pub fn show_with_aster(&self) { 17 | println!("*{}*", self.0); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/adaptor/enum_base.rs: -------------------------------------------------------------------------------- 1 | use crate::adaptor::Banner; 2 | 3 | pub enum Print { 4 | PrintBanner(Banner), 5 | } 6 | 7 | impl Print { 8 | pub fn of_print(banner: Banner) -> Self { 9 | Print::PrintBanner(banner) 10 | } 11 | 12 | pub fn print_weak(&self) { 13 | match self { 14 | Print::PrintBanner(b) => b.show_with_paren(), 15 | } 16 | } 17 | 18 | pub fn print_strong(&self) { 19 | match self { 20 | Print::PrintBanner(b) => b.show_with_aster(), 21 | } 22 | } 23 | } 24 | 25 | #[cfg(test)] 26 | mod test { 27 | use super::*; 28 | 29 | #[test] 30 | fn test() { 31 | // BannerをPrintとして扱える 32 | let p: Print = Print::of_print(Banner::new("Hello")); 33 | fn print(p: &Print) { 34 | p.print_weak(); 35 | p.print_strong(); 36 | } 37 | print(&p) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/adaptor/trait_base.rs: -------------------------------------------------------------------------------- 1 | use crate::adaptor::Banner; 2 | 3 | pub trait Print { 4 | fn print_weak(&self); 5 | fn print_strong(&self); 6 | } 7 | 8 | #[derive(Debug)] 9 | pub struct PrintBanner(Banner); 10 | 11 | impl PrintBanner { 12 | pub fn new(banner: Banner) -> Self { 13 | Self(banner) 14 | } 15 | } 16 | 17 | impl Print for PrintBanner { 18 | fn print_weak(&self) { 19 | self.0.show_with_paren(); 20 | } 21 | 22 | fn print_strong(&self) { 23 | self.0.show_with_aster(); 24 | } 25 | } 26 | 27 | #[cfg(test)] 28 | mod test { 29 | use super::*; 30 | 31 | #[test] 32 | fn test() { 33 | // BannerをPrintとして扱える 34 | let print_banner = PrintBanner::new(Banner::new("Hello")); 35 | fn print(p: &dyn Print) { 36 | p.print_weak(); 37 | p.print_strong(); 38 | } 39 | print(&print_banner) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/bridge.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod generic_base; 3 | mod trait_base; 4 | -------------------------------------------------------------------------------- /src/bridge/enum_base.rs: -------------------------------------------------------------------------------- 1 | pub enum Display { 2 | Default(DisplayImpl), 3 | Count(CountDisplay), 4 | } 5 | 6 | pub struct CountDisplay(Box); 7 | 8 | impl CountDisplay { 9 | pub fn multi_display(&mut self, times: u32) { 10 | self.0.open(); 11 | for i in 0..times { 12 | self.0.print(); 13 | } 14 | self.0.close(); 15 | } 16 | } 17 | 18 | impl Display { 19 | pub fn of_default(imp: DisplayImpl) -> Self { 20 | Display::Default(imp) 21 | } 22 | 23 | pub fn of_count(imp: DisplayImpl) -> Self { 24 | Display::Count(CountDisplay(Box::new(Self::of_default(imp)))) 25 | } 26 | 27 | pub fn open(&mut self) { 28 | match self { 29 | Display::Default(underlying) => underlying.raw_open(), 30 | Display::Count(underlying) => underlying.0.open(), 31 | } 32 | } 33 | 34 | pub fn print(&self) { 35 | match self { 36 | Display::Default(underlying) => underlying.raw_print(), 37 | Display::Count(underlying) => underlying.0.print(), 38 | } 39 | } 40 | 41 | pub fn close(&mut self) { 42 | match self { 43 | Display::Default(underlying) => underlying.raw_close(), 44 | Display::Count(underlying) => underlying.0.close(), 45 | } 46 | } 47 | 48 | pub fn display(&mut self) { 49 | match self { 50 | Display::Default(underlying) => { 51 | self.open(); 52 | self.print(); 53 | self.close(); 54 | } 55 | Display::Count(underlying) => underlying.0.display(), 56 | } 57 | } 58 | 59 | pub fn as_count_display_mut(&mut self) -> Option<&mut CountDisplay> { 60 | match self { 61 | Display::Count(c) => Some(c), 62 | _ => None, 63 | } 64 | } 65 | } 66 | 67 | pub enum DisplayImpl { 68 | String(String, u32), 69 | } 70 | 71 | impl DisplayImpl { 72 | pub fn of_string(s: &str) -> Self { 73 | DisplayImpl::String(s.to_owned(), 0) 74 | } 75 | 76 | fn print_line(&self) { 77 | match self { 78 | DisplayImpl::String(.., width) => { 79 | print!("+"); 80 | for _ in 0..*width { 81 | print!("-") 82 | } 83 | println!("+"); 84 | } 85 | } 86 | } 87 | 88 | fn raw_open(&mut self) { 89 | match self { 90 | DisplayImpl::String(..) => self.print_line(), 91 | } 92 | } 93 | 94 | fn raw_print(&self) { 95 | match self { 96 | DisplayImpl::String(string, ..) => println!("|{}|", string), 97 | } 98 | } 99 | 100 | fn raw_close(&mut self) { 101 | self.print_line(); 102 | } 103 | } 104 | 105 | #[cfg(test)] 106 | mod test { 107 | use super::*; 108 | 109 | #[test] 110 | fn test() { 111 | let mut d1 = Display::of_default(DisplayImpl::of_string("Hello, Japan.")); 112 | let mut d2 = Display::of_default(DisplayImpl::of_string("Hello, World")); 113 | let mut d3 = Display::of_count(DisplayImpl::of_string("Hello, Universe.")); 114 | d1.display(); 115 | d2.display(); 116 | d3.display(); 117 | d3.as_count_display_mut().unwrap().multi_display(5); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/bridge/generic_base.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | pub trait Display { 4 | fn open(&mut self); 5 | fn print(&self); 6 | fn close(&mut self); 7 | fn display(&mut self); 8 | } 9 | 10 | #[derive(Debug)] 11 | pub struct DisplayDefault { 12 | underlying: DI, 13 | } 14 | 15 | impl DisplayDefault { 16 | pub fn new(underlying: DI) -> Self { 17 | Self { underlying } 18 | } 19 | } 20 | 21 | impl Display for DisplayDefault { 22 | fn open(&mut self) { 23 | self.underlying.raw_open(); 24 | } 25 | 26 | fn print(&self) { 27 | self.underlying.raw_print(); 28 | } 29 | 30 | fn close(&mut self) { 31 | self.underlying.raw_close(); 32 | } 33 | 34 | fn display(&mut self) { 35 | self.open(); 36 | self.print(); 37 | self.close(); 38 | } 39 | } 40 | 41 | #[derive(Debug)] 42 | pub struct CountDisplay { 43 | underlying: DisplayDefault, 44 | } 45 | 46 | impl CountDisplay { 47 | pub fn new(underlying: DI) -> Self { 48 | Self { 49 | underlying: DisplayDefault::new(underlying), 50 | } 51 | } 52 | 53 | pub fn multi_display(&mut self, times: u32) { 54 | self.open(); 55 | for i in 0..times { 56 | self.print(); 57 | } 58 | self.close(); 59 | } 60 | } 61 | 62 | impl Display for CountDisplay { 63 | fn open(&mut self) { 64 | self.underlying.open(); 65 | } 66 | 67 | fn print(&self) { 68 | self.underlying.print(); 69 | } 70 | 71 | fn close(&mut self) { 72 | self.underlying.close(); 73 | } 74 | 75 | fn display(&mut self) { 76 | self.underlying.display(); 77 | } 78 | } 79 | 80 | pub trait DisplayImpl: Debug { 81 | fn raw_open(&mut self); 82 | fn raw_print(&self); 83 | fn raw_close(&mut self); 84 | } 85 | 86 | #[derive(Debug)] 87 | pub struct StringDisplayImpl { 88 | string: String, 89 | width: u32, 90 | } 91 | 92 | impl StringDisplayImpl { 93 | pub fn new(string: &str) -> Self { 94 | Self { 95 | string: string.to_owned(), 96 | width: 0, 97 | } 98 | } 99 | 100 | fn print_line(&self) { 101 | print!("+"); 102 | for _ in 0..self.width { 103 | print!("-") 104 | } 105 | println!("+"); 106 | } 107 | } 108 | 109 | impl DisplayImpl for StringDisplayImpl { 110 | fn raw_open(&mut self) { 111 | self.print_line(); 112 | } 113 | 114 | fn raw_print(&self) { 115 | println!("|{}|", self.string); 116 | } 117 | 118 | fn raw_close(&mut self) { 119 | self.print_line(); 120 | } 121 | } 122 | 123 | #[cfg(test)] 124 | mod test { 125 | use super::*; 126 | 127 | #[test] 128 | fn test() { 129 | let mut d1 = DisplayDefault::new(StringDisplayImpl::new("Hello, Japan.")); 130 | let mut d2 = DisplayDefault::new(StringDisplayImpl::new("Hello, World")); 131 | let mut d3 = CountDisplay::new(StringDisplayImpl::new("Hello, Universe.")); 132 | d1.display(); 133 | d2.display(); 134 | d3.display(); 135 | d3.multi_display(5); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/bridge/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | pub trait Display { 4 | fn open(&mut self); 5 | fn print(&self); 6 | fn close(&mut self); 7 | fn display(&mut self); 8 | } 9 | 10 | #[derive(Debug)] 11 | pub struct DisplayDefault { 12 | underlying: Box, 13 | } 14 | 15 | impl DisplayDefault { 16 | pub fn new(underlying: Box) -> Self { 17 | Self { underlying } 18 | } 19 | } 20 | 21 | impl Display for DisplayDefault { 22 | fn open(&mut self) { 23 | self.underlying.raw_open(); 24 | } 25 | 26 | fn print(&self) { 27 | self.underlying.raw_print(); 28 | } 29 | 30 | fn close(&mut self) { 31 | self.underlying.raw_close(); 32 | } 33 | 34 | fn display(&mut self) { 35 | self.open(); 36 | self.print(); 37 | self.close(); 38 | } 39 | } 40 | 41 | #[derive(Debug)] 42 | pub struct CountDisplay { 43 | underlying: DisplayDefault, 44 | } 45 | 46 | impl CountDisplay { 47 | pub fn new(underlying: Box) -> Self { 48 | Self { 49 | underlying: DisplayDefault::new(underlying), 50 | } 51 | } 52 | 53 | pub fn multi_display(&mut self, times: u32) { 54 | self.open(); 55 | for i in 0..times { 56 | self.print(); 57 | } 58 | self.close(); 59 | } 60 | } 61 | 62 | impl Display for CountDisplay { 63 | fn open(&mut self) { 64 | self.underlying.open(); 65 | } 66 | 67 | fn print(&self) { 68 | self.underlying.print(); 69 | } 70 | 71 | fn close(&mut self) { 72 | self.underlying.close(); 73 | } 74 | 75 | fn display(&mut self) { 76 | self.underlying.display(); 77 | } 78 | } 79 | 80 | pub trait DisplayImpl: Debug { 81 | fn raw_open(&mut self); 82 | fn raw_print(&self); 83 | fn raw_close(&mut self); 84 | } 85 | 86 | #[derive(Debug)] 87 | pub struct StringDisplayImpl { 88 | string: String, 89 | width: u32, 90 | } 91 | 92 | impl StringDisplayImpl { 93 | pub fn new(string: &str) -> Self { 94 | Self { 95 | string: string.to_owned(), 96 | width: 0, 97 | } 98 | } 99 | 100 | fn print_line(&self) { 101 | print!("+"); 102 | for _ in 0..self.width { 103 | print!("-") 104 | } 105 | println!("+"); 106 | } 107 | } 108 | 109 | impl DisplayImpl for StringDisplayImpl { 110 | fn raw_open(&mut self) { 111 | self.print_line(); 112 | } 113 | 114 | fn raw_print(&self) { 115 | println!("|{}|", self.string); 116 | } 117 | 118 | fn raw_close(&mut self) { 119 | self.print_line(); 120 | } 121 | } 122 | 123 | #[cfg(test)] 124 | mod test { 125 | use super::*; 126 | 127 | #[test] 128 | fn test() { 129 | let mut d1: Box = Box::new(DisplayDefault::new(Box::new(StringDisplayImpl::new("Hello, Japan.")))); 130 | let mut d2: Box = Box::new(DisplayDefault::new(Box::new(StringDisplayImpl::new("Hello, World")))); 131 | let mut d3: CountDisplay = CountDisplay::new(Box::new(StringDisplayImpl::new("Hello, Universe."))); 132 | d1.display(); 133 | d2.display(); 134 | d3.display(); 135 | d3.multi_display(5); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/builder.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::fmt::Debug; 3 | use std::fs::File; 4 | use std::io::{BufWriter, Write}; 5 | use std::rc::Rc; 6 | 7 | pub trait Builder: Debug { 8 | fn make_title(&mut self, title: &str); 9 | fn make_string(&mut self, str: &str); 10 | fn make_items(&mut self, items: &[&str]); 11 | fn close(&mut self); 12 | } 13 | 14 | #[derive(Debug)] 15 | pub struct Director { 16 | builder: Rc>, 17 | } 18 | 19 | impl Director { 20 | pub fn new(builder: Rc>) -> Self { 21 | Self { builder } 22 | } 23 | 24 | pub fn build(&self) { 25 | let mut builder = self.builder.borrow_mut(); 26 | builder.make_title("Greeting"); 27 | builder.make_string("一般的なあいさつ"); 28 | builder.make_items(&["How are you?", "Hello.", "Hi."]); 29 | builder.make_title("時間帯に応じたあいさつ"); 30 | builder.make_string("一般的なあいさつ"); 31 | builder.make_items(&["Good morning.", "Good afternoon.", "Good evening."]); 32 | builder.close(); 33 | } 34 | } 35 | 36 | #[derive(Debug)] 37 | pub struct TextBuilder { 38 | string: String, 39 | } 40 | 41 | impl TextBuilder { 42 | pub fn new() -> Self { 43 | Self { string: "".to_owned() } 44 | } 45 | 46 | pub fn get_text_result(&self) -> &str { 47 | &self.string 48 | } 49 | } 50 | 51 | impl Builder for TextBuilder { 52 | fn make_title(&mut self, title: &str) { 53 | self.string.push_str("==============================\n"); 54 | self.string.push('『'); 55 | self.string.push_str(title); 56 | self.string.push_str("』\n\n"); 57 | } 58 | 59 | fn make_string(&mut self, str: &str) { 60 | self.string.push('■'); 61 | self.string.push_str(str); 62 | self.string.push_str("\n\n"); 63 | } 64 | 65 | fn make_items(&mut self, items: &[&str]) { 66 | for s in items { 67 | self.string.push_str(" ・"); 68 | self.string.push_str(s); 69 | self.string.push('\n'); 70 | } 71 | } 72 | 73 | fn close(&mut self) { 74 | self.string.push_str("==============================\n"); 75 | } 76 | } 77 | 78 | #[derive(Debug)] 79 | pub struct HtmlBuilder { 80 | file_name: Option, 81 | string: String, 82 | } 83 | 84 | impl HtmlBuilder { 85 | pub fn new() -> Self { 86 | Self { 87 | file_name: None, 88 | string: "".to_owned(), 89 | } 90 | } 91 | 92 | pub fn get_html_result(&self) -> &str { 93 | self.file_name.as_ref().unwrap() 94 | } 95 | } 96 | 97 | impl Builder for HtmlBuilder { 98 | fn make_title(&mut self, title: &str) { 99 | self.file_name = Some(format!("{}.html", title)); 100 | self.string.push_str("\n"); 101 | self.string.push_str("\n"); 102 | self.string.push_str(""); 103 | self.string.push_str(title); 104 | self.string.push_str("\n"); 105 | self.string.push_str("\n"); 106 | self.string.push_str("

"); 107 | self.string.push_str(title); 108 | self.string.push_str("

\n\n"); 109 | } 110 | 111 | fn make_string(&mut self, str: &str) { 112 | self.string.push_str("

"); 113 | self.string.push_str(str); 114 | self.string.push_str("

\n\n") 115 | } 116 | 117 | fn make_items(&mut self, items: &[&str]) { 118 | self.string.push_str("
    \n"); 119 | for s in items { 120 | self.string.push_str("
  • "); 121 | self.string.push_str(s); 122 | self.string.push_str("
  • \n"); 123 | } 124 | self.string.push_str("
\n\n") 125 | } 126 | 127 | fn close(&mut self) { 128 | self.string.push_str(""); 129 | self.string.push_str("\n"); 130 | let mut writer = BufWriter::new(File::create(self.file_name.as_ref().unwrap().clone()).unwrap()); 131 | writer.write(self.string.as_bytes()).unwrap(); 132 | } 133 | } 134 | 135 | #[cfg(test)] 136 | mod test { 137 | use super::*; 138 | 139 | #[test] 140 | fn test() { 141 | let builder = Rc::new(RefCell::new(TextBuilder::new())); 142 | let director = Director::new(builder.clone()); 143 | director.build(); 144 | let builder_ref = builder.borrow(); 145 | let result = builder_ref.get_text_result(); 146 | println!("{}", result); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/chain_of_responsibility.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter}; 2 | 3 | mod enum_base; 4 | mod trait_base; 5 | 6 | #[derive(Debug)] 7 | pub struct Trouble { 8 | number: u32, 9 | } 10 | 11 | impl Display for Trouble { 12 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 13 | write!(f, "[Trouble {}]", self.number) 14 | } 15 | } 16 | 17 | impl Trouble { 18 | pub fn new(number: u32) -> Self { 19 | Self { number } 20 | } 21 | 22 | pub fn number(&self) -> u32 { 23 | self.number 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/chain_of_responsibility/enum_base.rs: -------------------------------------------------------------------------------- 1 | use crate::chain_of_responsibility::Trouble; 2 | use std::fmt::{Debug, Display, Formatter}; 3 | use std::rc::Rc; 4 | 5 | #[derive(Debug)] 6 | pub enum Support { 7 | No(NoSupport), 8 | Limit(LimitSupport), 9 | Odd(OddSupport), 10 | Special(SpecialSupport), 11 | } 12 | 13 | impl Support { 14 | pub fn of_no(name: &str, next: Option>) -> Self { 15 | Support::No(NoSupport::new(name, next)) 16 | } 17 | 18 | pub fn of_limit(name: &str, limit: u32, next: Option>) -> Self { 19 | Support::Limit(LimitSupport::new(name, limit, next)) 20 | } 21 | 22 | pub fn of_odd(name: &str, next: Option>) -> Self { 23 | Support::Odd(OddSupport::new(name, next)) 24 | } 25 | 26 | pub fn of_special(name: &str, number: u32, next: Option>) -> Self { 27 | Support::Special(SpecialSupport::new(name, number, next)) 28 | } 29 | 30 | pub fn support(&self, trouble: &Trouble) { 31 | match self { 32 | Support::No(u) => u.support(trouble), 33 | Support::Limit(u) => u.support(trouble), 34 | Support::Odd(u) => u.support(trouble), 35 | Support::Special(u) => u.support(trouble), 36 | } 37 | } 38 | } 39 | 40 | trait SupportBehaviorBase: std::fmt::Display + Debug { 41 | fn done(&self, trouble: &Trouble) { 42 | println!("{} is resolved by {}.", trouble, self); 43 | } 44 | fn fail(&self, trouble: &Trouble) { 45 | println!("{} cannot be resolved.", trouble); 46 | } 47 | fn next(&self) -> Option>; 48 | } 49 | 50 | pub trait SupportBehavior: SupportBehaviorBase { 51 | fn resolve(&self, trouble: &Trouble) -> bool; 52 | 53 | fn support(&self, trouble: &Trouble) { 54 | if self.resolve(trouble) { 55 | self.done(trouble); 56 | } else if self.next().is_some() { 57 | let next_rc = self.next().unwrap(); 58 | let next_ref = &*next_rc; 59 | next_ref.support(trouble); 60 | } else { 61 | self.fail(trouble); 62 | } 63 | } 64 | } 65 | 66 | #[derive(Debug)] 67 | pub struct NoSupport { 68 | name: String, 69 | next: Option>, 70 | } 71 | 72 | impl NoSupport { 73 | pub fn new(name: &str, next: Option>) -> Self { 74 | Self { 75 | name: name.to_owned(), 76 | next, 77 | } 78 | } 79 | } 80 | 81 | impl SupportBehaviorBase for NoSupport { 82 | fn next(&self) -> Option> { 83 | self.next.clone() 84 | } 85 | } 86 | 87 | impl Display for NoSupport { 88 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 89 | write!(f, "[{}@NoSupport]", self.name) 90 | } 91 | } 92 | 93 | impl SupportBehavior for NoSupport { 94 | fn resolve(&self, trouble: &Trouble) -> bool { 95 | // print!("NoSupport: false "); 96 | false 97 | } 98 | } 99 | 100 | #[derive(Debug)] 101 | pub struct LimitSupport { 102 | name: String, 103 | next: Option>, 104 | limit: u32, 105 | } 106 | 107 | impl LimitSupport { 108 | pub fn new(name: &str, limit: u32, next: Option>) -> Self { 109 | Self { 110 | name: name.to_owned(), 111 | next, 112 | limit, 113 | } 114 | } 115 | } 116 | 117 | impl SupportBehaviorBase for LimitSupport { 118 | fn next(&self) -> Option> { 119 | self.next.clone() 120 | } 121 | } 122 | 123 | impl Display for LimitSupport { 124 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 125 | write!(f, "[{}@LimitSupport]", self.name) 126 | } 127 | } 128 | 129 | impl SupportBehavior for LimitSupport { 130 | fn resolve(&self, trouble: &Trouble) -> bool { 131 | trouble.number() < self.limit 132 | } 133 | } 134 | 135 | #[derive(Debug)] 136 | pub struct OddSupport { 137 | name: String, 138 | next: Option>, 139 | } 140 | 141 | impl OddSupport { 142 | pub fn new(name: &str, next: Option>) -> Self { 143 | Self { 144 | name: name.to_owned(), 145 | next, 146 | } 147 | } 148 | } 149 | 150 | impl SupportBehaviorBase for OddSupport { 151 | fn next(&self) -> Option> { 152 | self.next.clone() 153 | } 154 | } 155 | 156 | impl Display for OddSupport { 157 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 158 | write!(f, "[{}@OddSupport]", self.name) 159 | } 160 | } 161 | 162 | impl SupportBehavior for OddSupport { 163 | fn resolve(&self, trouble: &Trouble) -> bool { 164 | trouble.number() % 2 == 1 165 | } 166 | } 167 | 168 | #[derive(Debug)] 169 | pub struct SpecialSupport { 170 | name: String, 171 | next: Option>, 172 | number: u32, 173 | } 174 | 175 | impl SpecialSupport { 176 | pub fn new(name: &str, number: u32, next: Option>) -> Self { 177 | Self { 178 | name: name.to_owned(), 179 | next, 180 | number, 181 | } 182 | } 183 | } 184 | 185 | impl SupportBehaviorBase for SpecialSupport { 186 | fn next(&self) -> Option> { 187 | self.next.clone() 188 | } 189 | } 190 | 191 | impl Display for SpecialSupport { 192 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 193 | write!(f, "[{}@SpecialSupport]", self.name) 194 | } 195 | } 196 | 197 | impl SupportBehavior for SpecialSupport { 198 | fn resolve(&self, trouble: &Trouble) -> bool { 199 | trouble.number() == self.number 200 | } 201 | } 202 | 203 | #[cfg(test)] 204 | mod test { 205 | 206 | use super::*; 207 | 208 | #[test] 209 | fn test() { 210 | let fred = Rc::new(Support::of_limit("Fred", 300, None)); 211 | let elmo = Rc::new(Support::of_odd("Elmo", Some(fred))); 212 | let diana = Rc::new(Support::of_limit("Diana", 200, Some(elmo))); 213 | let charlie = Rc::new(Support::of_special("Charlie", 429, Some(diana))); 214 | let bob = Rc::new(Support::of_limit("Bob", 100, Some(charlie))); 215 | let alice = Support::of_no("Alice", Some(bob)); 216 | 217 | for i in (0..500).step_by(33) { 218 | let t = Trouble::new(i); 219 | alice.support(&t); 220 | } 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/chain_of_responsibility/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Debug, Display, Formatter}; 2 | use std::rc::Rc; 3 | 4 | use crate::chain_of_responsibility::Trouble; 5 | 6 | trait SupportBase: std::fmt::Display + Debug { 7 | fn done(&self, trouble: &Trouble) { 8 | println!("{} is resolved by {}.", trouble, self); 9 | } 10 | fn fail(&self, trouble: &Trouble) { 11 | println!("{} cannot be resolved.", trouble); 12 | } 13 | fn next(&self) -> Option>; 14 | } 15 | 16 | pub trait Support: SupportBase { 17 | fn resolve(&self, trouble: &Trouble) -> bool; 18 | 19 | fn support(&self, trouble: &Trouble) { 20 | if self.resolve(trouble) { 21 | self.done(trouble); 22 | } else if self.next().is_some() { 23 | let next_rc = self.next().unwrap(); 24 | let next_ref = &*next_rc; 25 | next_ref.support(trouble); 26 | } else { 27 | self.fail(trouble); 28 | } 29 | } 30 | } 31 | 32 | // --- 33 | 34 | #[derive(Debug)] 35 | pub struct NoSupport { 36 | name: String, 37 | next: Option>, 38 | } 39 | 40 | impl NoSupport { 41 | pub fn new(name: &str, next: Option>) -> Self { 42 | Self { 43 | name: name.to_owned(), 44 | next, 45 | } 46 | } 47 | } 48 | 49 | impl Display for NoSupport { 50 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 51 | write!(f, "[{}@NoSupport]", self.name) 52 | } 53 | } 54 | 55 | impl SupportBase for NoSupport { 56 | fn next(&self) -> Option> { 57 | self.next.clone() 58 | } 59 | } 60 | 61 | impl Support for NoSupport { 62 | fn resolve(&self, trouble: &Trouble) -> bool { 63 | // print!("NoSupport: false "); 64 | false 65 | } 66 | } 67 | 68 | // --- 69 | 70 | #[derive(Debug)] 71 | pub struct LimitSupport { 72 | name: String, 73 | next: Option>, 74 | limit: u32, 75 | } 76 | 77 | impl LimitSupport { 78 | pub fn new(name: &str, limit: u32, next: Option>) -> Self { 79 | Self { 80 | name: name.to_owned(), 81 | next, 82 | limit, 83 | } 84 | } 85 | } 86 | 87 | impl SupportBase for LimitSupport { 88 | fn next(&self) -> Option> { 89 | self.next.clone() 90 | } 91 | } 92 | 93 | impl Display for LimitSupport { 94 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 95 | write!(f, "[{}@LimitSupport]", self.name) 96 | } 97 | } 98 | 99 | impl Support for LimitSupport { 100 | fn resolve(&self, trouble: &Trouble) -> bool { 101 | trouble.number() < self.limit 102 | } 103 | } 104 | 105 | // --- 106 | 107 | #[derive(Debug)] 108 | pub struct OddSupport { 109 | name: String, 110 | next: Option>, 111 | } 112 | 113 | impl OddSupport { 114 | pub fn new(name: &str, next: Option>) -> Self { 115 | Self { 116 | name: name.to_owned(), 117 | next, 118 | } 119 | } 120 | } 121 | 122 | impl SupportBase for OddSupport { 123 | fn next(&self) -> Option> { 124 | self.next.clone() 125 | } 126 | } 127 | 128 | impl Display for OddSupport { 129 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 130 | write!(f, "[{}@OddSupport]", self.name) 131 | } 132 | } 133 | 134 | impl Support for OddSupport { 135 | fn resolve(&self, trouble: &Trouble) -> bool { 136 | trouble.number() % 2 == 1 137 | } 138 | } 139 | 140 | // --- 141 | 142 | #[derive(Debug)] 143 | pub struct SpecialSupport { 144 | name: String, 145 | next: Option>, 146 | number: u32, 147 | } 148 | 149 | impl SpecialSupport { 150 | pub fn new(name: &str, number: u32, next: Option>) -> Self { 151 | Self { 152 | name: name.to_owned(), 153 | next, 154 | number, 155 | } 156 | } 157 | } 158 | 159 | impl SupportBase for SpecialSupport { 160 | fn next(&self) -> Option> { 161 | self.next.clone() 162 | } 163 | } 164 | 165 | impl Display for SpecialSupport { 166 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 167 | write!(f, "[{}@SpecialSupport]", self.name) 168 | } 169 | } 170 | 171 | impl Support for SpecialSupport { 172 | fn resolve(&self, trouble: &Trouble) -> bool { 173 | trouble.number() == self.number 174 | } 175 | } 176 | 177 | #[cfg(test)] 178 | mod test { 179 | 180 | use super::*; 181 | 182 | #[test] 183 | fn test() { 184 | let fred = Rc::new(LimitSupport::new("Fred", 300, None)); 185 | let elmo = Rc::new(OddSupport::new("Elmo", Some(fred))); 186 | let diana = Rc::new(LimitSupport::new("Diana", 200, Some(elmo))); 187 | let charlie = Rc::new(SpecialSupport::new("Charlie", 429, Some(diana))); 188 | let bob = Rc::new(LimitSupport::new("Bob", 100, Some(charlie))); 189 | let alice = NoSupport::new("Alice", Some(bob)); 190 | 191 | for i in (0..500).step_by(33) { 192 | let t = Trouble::new(i); 193 | alice.support(&t); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/command.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod generic_base; 3 | mod trait_base; 4 | -------------------------------------------------------------------------------- /src/command/enum_base.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | 3 | pub enum Command { 4 | Echo(String), 5 | Double(String), 6 | Macro(MacroCommand), 7 | } 8 | 9 | pub struct MacroCommand { 10 | commands: VecDeque, 11 | } 12 | 13 | impl MacroCommand { 14 | pub fn append(&mut self, cmd: Command) { 15 | self.commands.push_back(cmd); 16 | } 17 | 18 | pub fn undo(&mut self) { 19 | if !self.commands.is_empty() { 20 | self.commands.pop_front(); 21 | } 22 | } 23 | 24 | pub fn clear(&mut self) { 25 | self.commands.clear(); 26 | } 27 | } 28 | 29 | impl Command { 30 | pub fn of_echo(s: &str) -> Self { 31 | Command::Echo(s.to_owned()) 32 | } 33 | 34 | pub fn of_macro(commands: VecDeque) -> Self { 35 | Command::Macro(MacroCommand { commands }) 36 | } 37 | 38 | pub fn of_macro_with_empty_commands() -> Self { 39 | Command::Macro(MacroCommand { 40 | commands: VecDeque::new(), 41 | }) 42 | } 43 | 44 | pub fn as_macro(&self) -> Option<&MacroCommand> { 45 | match self { 46 | Command::Macro(m) => Some(m), 47 | _ => None, 48 | } 49 | } 50 | 51 | pub fn as_macro_mut(&mut self) -> Option<&mut MacroCommand> { 52 | match self { 53 | Command::Macro(m) => Some(m), 54 | _ => None, 55 | } 56 | } 57 | 58 | pub fn execute(&self) { 59 | match self { 60 | Command::Echo(s) => println!("{}", s), 61 | Command::Double(s) => println!("{}{}", s, s), 62 | Command::Macro(MacroCommand { commands }) => { 63 | for cmd in commands { 64 | cmd.execute(); 65 | } 66 | } 67 | } 68 | } 69 | } 70 | 71 | #[cfg(test)] 72 | mod test { 73 | use super::*; 74 | 75 | #[test] 76 | fn test() { 77 | let mut mc = Command::of_macro_with_empty_commands(); 78 | mc.as_macro_mut().unwrap().append(Command::of_echo("Hello")); 79 | mc.execute(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/command/generic_base.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | use std::fmt::Debug; 3 | 4 | pub trait Command: Debug { 5 | fn execute(&self); 6 | } 7 | 8 | #[derive(Debug)] 9 | pub struct MacroCommand { 10 | commands: VecDeque, 11 | } 12 | 13 | impl Command for MacroCommand { 14 | fn execute(&self) { 15 | for cmd in &self.commands { 16 | cmd.execute(); 17 | } 18 | } 19 | } 20 | 21 | impl MacroCommand { 22 | pub fn new() -> Self { 23 | Self { 24 | commands: VecDeque::new(), 25 | } 26 | } 27 | 28 | pub fn append(&mut self, cmd: C) { 29 | self.commands.push_back(cmd); 30 | } 31 | 32 | pub fn undo(&mut self) { 33 | if !self.commands.is_empty() { 34 | self.commands.pop_front(); 35 | } 36 | } 37 | 38 | pub fn clear(&mut self) { 39 | self.commands.clear(); 40 | } 41 | } 42 | 43 | #[derive(Debug)] 44 | struct EchoCommand { 45 | msg: String, 46 | } 47 | 48 | impl EchoCommand { 49 | pub fn new(msg: &str) -> Self { 50 | Self { msg: msg.to_owned() } 51 | } 52 | 53 | fn run(&self) { 54 | println!("{}", self.msg) 55 | } 56 | } 57 | 58 | impl Command for EchoCommand { 59 | fn execute(&self) { 60 | self.run() 61 | } 62 | } 63 | 64 | #[derive(Debug)] 65 | struct DoubleEchoCommand { 66 | msg: String, 67 | } 68 | 69 | impl DoubleEchoCommand { 70 | fn new(msg: &str) -> Self { 71 | Self { msg: msg.to_owned() } 72 | } 73 | } 74 | 75 | impl Command for DoubleEchoCommand { 76 | fn execute(&self) { 77 | println!("{}{}", self.msg, self.msg) 78 | } 79 | } 80 | 81 | #[cfg(test)] 82 | mod test { 83 | use super::*; 84 | 85 | #[test] 86 | fn test() { 87 | fn execute(cmd: &T) { 88 | cmd.execute() 89 | } 90 | 91 | let mut mc = MacroCommand::new(); 92 | mc.append(EchoCommand::new("Hello")); 93 | // コンパイルエラーになる 94 | // mc.append(DoubleEchoCommand::new("Hello")); 95 | execute(&mc); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/command/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::collections::VecDeque; 2 | use std::fmt::Debug; 3 | 4 | pub trait Command: Debug { 5 | fn execute(&self); 6 | } 7 | 8 | #[derive(Debug)] 9 | pub struct MacroCommand { 10 | commands: VecDeque>, 11 | } 12 | 13 | impl Command for MacroCommand { 14 | fn execute(&self) { 15 | for cmd in &self.commands { 16 | cmd.execute(); 17 | } 18 | } 19 | } 20 | 21 | impl MacroCommand { 22 | pub fn new() -> Self { 23 | Self { 24 | commands: VecDeque::new(), 25 | } 26 | } 27 | 28 | pub fn append(&mut self, cmd: Box) { 29 | self.commands.push_back(cmd); 30 | } 31 | 32 | pub fn undo(&mut self) { 33 | if !self.commands.is_empty() { 34 | self.commands.pop_back(); 35 | } 36 | } 37 | 38 | pub fn clear(&mut self) { 39 | self.commands.clear(); 40 | } 41 | } 42 | 43 | #[derive(Debug)] 44 | struct EchoCommand { 45 | msg: String, 46 | } 47 | 48 | impl EchoCommand { 49 | fn new(msg: &str) -> Self { 50 | Self { msg: msg.to_owned() } 51 | } 52 | } 53 | 54 | impl Command for EchoCommand { 55 | fn execute(&self) { 56 | println!("{}", self.msg) 57 | } 58 | } 59 | 60 | #[cfg(test)] 61 | mod test { 62 | use super::*; 63 | 64 | #[test] 65 | fn test() { 66 | let mut mc = MacroCommand::new(); 67 | mc.append(Box::new(EchoCommand::new("Hello"))); 68 | mc.execute(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/composite.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod generic_base; 3 | mod trait_base; 4 | -------------------------------------------------------------------------------- /src/composite/enum_base.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::fmt::{Display, Formatter}; 3 | use std::rc::Rc; 4 | 5 | #[derive(Debug)] 6 | pub struct File { 7 | name: String, 8 | size: usize, 9 | } 10 | 11 | #[derive(Debug)] 12 | pub struct Directory { 13 | name: String, 14 | entries: Vec>>, 15 | } 16 | 17 | #[derive(Debug)] 18 | pub enum Entry { 19 | File(File), 20 | Directory(Directory), 21 | } 22 | 23 | impl Display for Entry { 24 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 25 | match self { 26 | Entry::File(file) => write!(f, "{}", file), 27 | Entry::Directory(directory) => write!(f, "{}", directory), 28 | } 29 | } 30 | } 31 | 32 | impl Display for File { 33 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 34 | write!(f, "{} ({})", self.name, self.size) 35 | } 36 | } 37 | 38 | impl File { 39 | pub fn get_name(&self) -> &str { 40 | &self.name 41 | } 42 | 43 | pub fn get_size(&self) -> usize { 44 | self.size 45 | } 46 | 47 | fn print_line_with_prefix(&self, prefix: &str) { 48 | println!("{}/{}", prefix, self); 49 | } 50 | } 51 | 52 | impl Display for Directory { 53 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 54 | write!(f, "{} ({})", self.name, self.get_size()) 55 | } 56 | } 57 | 58 | impl Directory { 59 | pub fn get_name(&self) -> &str { 60 | &self.name 61 | } 62 | 63 | pub fn add(&mut self, entry: Rc>) { 64 | self.entries.push(entry); 65 | } 66 | 67 | pub fn get_size(&self) -> usize { 68 | self.entries.iter().fold(0, |r, e| r + e.borrow().get_size()) 69 | } 70 | 71 | fn print_line_with_prefix(&self, prefix: &str) { 72 | println!("{}/{}", prefix, self); 73 | for entry in &self.entries { 74 | let entry_ref = (**entry).borrow(); 75 | entry_ref.print_line_with_prefix(&format!("{}/{}", prefix, self.name)) 76 | } 77 | } 78 | } 79 | 80 | impl Entry { 81 | pub fn of_file(name: &str, size: usize) -> Self { 82 | Entry::File(File { 83 | name: name.to_owned(), 84 | size, 85 | }) 86 | } 87 | 88 | pub fn of_directory(name: &str) -> Self { 89 | Entry::Directory(Directory { 90 | name: name.to_owned(), 91 | entries: vec![], 92 | }) 93 | } 94 | 95 | fn print_line_with_prefix(&self, prefix: &str) { 96 | match self { 97 | Entry::File(f) => f.print_line_with_prefix(prefix), 98 | Entry::Directory(d) => d.print_line_with_prefix(prefix), 99 | } 100 | } 101 | 102 | pub fn get_name(&self) -> &str { 103 | match self { 104 | Entry::File(f) => f.get_name(), 105 | Entry::Directory(d) => d.get_name(), 106 | } 107 | } 108 | 109 | pub fn get_size(&self) -> usize { 110 | match self { 111 | Entry::File(f) => f.get_size(), 112 | Entry::Directory(d) => d.get_size(), 113 | } 114 | } 115 | 116 | pub fn print_line(&self) { 117 | self.print_line_with_prefix(""); 118 | } 119 | 120 | pub fn as_file(&self) -> Option<&File> { 121 | match self { 122 | Entry::File(d) => Some(d), 123 | _ => None, 124 | } 125 | } 126 | 127 | pub fn as_directory(&self) -> Option<&Directory> { 128 | match self { 129 | Entry::Directory(d) => Some(d), 130 | _ => None, 131 | } 132 | } 133 | 134 | pub fn as_directory_mut(&mut self) -> Option<&mut Directory> { 135 | match self { 136 | Entry::Directory(d) => Some(d), 137 | _ => None, 138 | } 139 | } 140 | } 141 | 142 | #[cfg(test)] 143 | mod test { 144 | use std::borrow::BorrowMut; 145 | use std::cell::RefCell; 146 | 147 | use super::*; 148 | 149 | #[test] 150 | fn test() { 151 | let mut rootdir = Entry::of_directory("root"); 152 | let bindir = Rc::new(RefCell::new(Entry::of_directory("bin"))); 153 | let tmpdir = Rc::new(RefCell::new(Entry::of_directory("tmp"))); 154 | let usrdir = Rc::new(RefCell::new(Entry::of_directory("usr"))); 155 | 156 | rootdir.as_directory_mut().unwrap().add(bindir.clone()); 157 | rootdir.as_directory_mut().unwrap().add(tmpdir.clone()); 158 | rootdir.as_directory_mut().unwrap().add(usrdir.clone()); 159 | 160 | { 161 | let mut bindir_ref = (&*bindir).borrow_mut(); 162 | bindir_ref 163 | .as_directory_mut() 164 | .unwrap() 165 | .add(Rc::new(RefCell::new(Entry::of_file("vi", 10000)))); 166 | bindir_ref 167 | .as_directory_mut() 168 | .unwrap() 169 | .add(Rc::new(RefCell::new(Entry::of_file("latex", 20000)))); 170 | // bindir_ref.print_line(); 171 | } 172 | 173 | let yuki = Rc::new(RefCell::new(Entry::of_directory("yuki"))); 174 | let hanako = Rc::new(RefCell::new(Entry::of_directory("hanako"))); 175 | let tomura = Rc::new(RefCell::new(Entry::of_directory("tomura"))); 176 | 177 | { 178 | let mut usrdir_ref = (&*usrdir).borrow_mut(); 179 | usrdir_ref.as_directory_mut().unwrap().add(yuki.clone()); 180 | usrdir_ref.as_directory_mut().unwrap().add(hanako.clone()); 181 | usrdir_ref.as_directory_mut().unwrap().add(tomura.clone()); 182 | // usrdir_ref.print_line(); 183 | } 184 | 185 | { 186 | let mut yuki_ref = (&*yuki).borrow_mut(); 187 | yuki_ref 188 | .as_directory_mut() 189 | .unwrap() 190 | .add(Rc::new(RefCell::new(Entry::of_file("diary.html", 100)))); 191 | yuki_ref 192 | .as_directory_mut() 193 | .unwrap() 194 | .add(Rc::new(RefCell::new(Entry::of_file("Composite.java", 200)))); 195 | // yuki_ref.print_line(); 196 | } 197 | 198 | { 199 | let mut hanako_ref = (&*hanako).borrow_mut(); 200 | hanako_ref 201 | .as_directory_mut() 202 | .unwrap() 203 | .add(Rc::new(RefCell::new(Entry::of_file("memo.tex", 300)))); 204 | // hanako_ref.print_line(); 205 | } 206 | 207 | { 208 | let mut tomura_ref = (&*tomura).borrow_mut(); 209 | tomura_ref 210 | .as_directory_mut() 211 | .unwrap() 212 | .add(Rc::new(RefCell::new(Entry::of_file("game.doc", 400)))); 213 | tomura_ref 214 | .as_directory_mut() 215 | .unwrap() 216 | .add(Rc::new(RefCell::new(Entry::of_file("junk.mail", 500)))); 217 | // tomura_ref.print_line(); 218 | } 219 | 220 | rootdir.print_line(); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/composite/generic_base.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::fmt::{Debug, Display, Formatter}; 3 | use std::rc::Rc; 4 | 5 | trait EntryBase { 6 | fn print_line_with_prefix(&self, prefix: &str); 7 | } 8 | 9 | pub trait Entry: EntryBase + Display + Debug { 10 | fn get_name(&self) -> &str; 11 | fn get_size(&self) -> usize; 12 | fn print_line(&self) { 13 | self.print_line_with_prefix(""); 14 | } 15 | } 16 | 17 | #[derive(Debug)] 18 | pub struct File { 19 | name: String, 20 | size: usize, 21 | } 22 | 23 | impl File { 24 | pub fn new(name: &str, size: usize) -> Self { 25 | Self { 26 | name: name.to_owned(), 27 | size, 28 | } 29 | } 30 | } 31 | 32 | impl EntryBase for File { 33 | fn print_line_with_prefix(&self, prefix: &str) { 34 | println!("{}/{}", prefix, self) 35 | } 36 | } 37 | 38 | impl Display for File { 39 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 40 | write!(f, "{} ({})", self.name, self.size) 41 | } 42 | } 43 | 44 | impl Entry for File { 45 | fn get_name(&self) -> &str { 46 | &self.name 47 | } 48 | 49 | fn get_size(&self) -> usize { 50 | self.size 51 | } 52 | } 53 | 54 | #[derive(Debug)] 55 | pub struct Directory { 56 | name: String, 57 | entries: Vec>>, 58 | } 59 | 60 | impl Directory { 61 | pub fn new(name: &str) -> Self { 62 | Self { 63 | name: name.to_owned(), 64 | entries: Vec::new(), 65 | } 66 | } 67 | 68 | pub fn add(&mut self, entry: Rc>) { 69 | self.entries.push(entry); 70 | } 71 | } 72 | 73 | impl EntryBase for Directory { 74 | fn print_line_with_prefix(&self, prefix: &str) { 75 | println!("{}/{}", prefix, self); 76 | for entry in &self.entries { 77 | let entry_ref = (**entry).borrow(); 78 | entry_ref.print_line_with_prefix(&format!("{}/{}", prefix, self.name)) 79 | } 80 | } 81 | } 82 | 83 | impl Display for Directory { 84 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 85 | write!(f, "{} ({})", self.name, self.get_size()) 86 | } 87 | } 88 | 89 | impl Entry for Directory { 90 | fn get_name(&self) -> &str { 91 | &self.name 92 | } 93 | 94 | fn get_size(&self) -> usize { 95 | self.entries.iter().fold(0, |r, e| r + e.borrow().get_size()) 96 | } 97 | } 98 | 99 | #[cfg(test)] 100 | mod test { 101 | use std::borrow::BorrowMut; 102 | use std::cell::RefCell; 103 | 104 | use super::*; 105 | 106 | #[test] 107 | fn test() { 108 | let mut rootdir = Directory::new("root"); 109 | let bindir = Rc::new(RefCell::new(Directory::new("bin"))); 110 | let tmpdir = Rc::new(RefCell::new(Directory::new("tmp"))); 111 | let usrdir = Rc::new(RefCell::new(Directory::new("usr"))); 112 | 113 | rootdir.add(bindir.clone()); 114 | rootdir.add(tmpdir.clone()); 115 | rootdir.add(usrdir.clone()); 116 | 117 | { 118 | let mut bindir_ref = (&*bindir).borrow_mut(); 119 | bindir_ref.add(Rc::new(RefCell::new(File::new("vi", 10000)))); 120 | bindir_ref.add(Rc::new(RefCell::new(File::new("latex", 20000)))); 121 | // bindir_ref.print_line(); 122 | } 123 | 124 | let yuki = Rc::new(RefCell::new(Directory::new("yuki"))); 125 | let hanako = Rc::new(RefCell::new(Directory::new("hanako"))); 126 | let tomura = Rc::new(RefCell::new(Directory::new("tomura"))); 127 | 128 | { 129 | let usrdir_ref = (&*usrdir).borrow_mut(); 130 | // userdirにはファイルしか追加できないが、ここでディレクトリを追加しようとしているので、このコードはコンパイルできない 131 | // usrdir_ref.add(yuki.clone()); 132 | // usrdir_ref.add(hanako.clone()); 133 | // usrdir_ref.add(tomura.clone()); 134 | // usrdir_ref.print_line(); 135 | } 136 | 137 | { 138 | let mut yuki_ref = (&*yuki).borrow_mut(); 139 | yuki_ref.add(Rc::new(RefCell::new(File::new("diary.html", 100)))); 140 | yuki_ref.add(Rc::new(RefCell::new(File::new("Composite.java", 200)))); 141 | // yuki_ref.print_line(); 142 | } 143 | 144 | { 145 | let mut hanako_ref = (&*hanako).borrow_mut(); 146 | hanako_ref.add(Rc::new(RefCell::new(File::new("memo.tex", 300)))); 147 | // hanako_ref.print_line(); 148 | } 149 | 150 | { 151 | let mut tomura_ref = (&*tomura).borrow_mut(); 152 | tomura_ref.add(Rc::new(RefCell::new(File::new("game.doc", 400)))); 153 | tomura_ref.add(Rc::new(RefCell::new(File::new("junk.mail", 500)))); 154 | // tomura_ref.print_line(); 155 | } 156 | 157 | rootdir.print_line(); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/composite/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::fmt::{Debug, Display, Formatter}; 3 | use std::rc::Rc; 4 | 5 | trait EntryBase { 6 | fn print_line_with_prefix(&self, prefix: &str); 7 | } 8 | 9 | pub trait Entry: EntryBase + Display + Debug { 10 | fn get_name(&self) -> &str; 11 | fn get_size(&self) -> usize; 12 | fn print_line(&self) { 13 | self.print_line_with_prefix(""); 14 | } 15 | } 16 | 17 | #[derive(Debug)] 18 | pub struct File { 19 | name: String, 20 | size: usize, 21 | } 22 | 23 | impl File { 24 | pub fn new(name: &str, size: usize) -> Self { 25 | Self { 26 | name: name.to_owned(), 27 | size, 28 | } 29 | } 30 | } 31 | 32 | impl EntryBase for File { 33 | fn print_line_with_prefix(&self, prefix: &str) { 34 | println!("{}/{}", prefix, self) 35 | } 36 | } 37 | 38 | impl Display for File { 39 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 40 | write!(f, "{} ({})", self.name, self.size) 41 | } 42 | } 43 | 44 | impl Entry for File { 45 | fn get_name(&self) -> &str { 46 | &self.name 47 | } 48 | 49 | fn get_size(&self) -> usize { 50 | self.size 51 | } 52 | } 53 | 54 | #[derive(Debug)] 55 | pub struct Directory { 56 | name: String, 57 | entries: Vec>>, 58 | } 59 | 60 | impl Directory { 61 | pub fn new(name: &str) -> Self { 62 | Self { 63 | name: name.to_owned(), 64 | entries: Vec::new(), 65 | } 66 | } 67 | 68 | pub fn add(&mut self, entry: Rc>) { 69 | self.entries.push(entry); 70 | } 71 | } 72 | 73 | impl EntryBase for Directory { 74 | fn print_line_with_prefix(&self, prefix: &str) { 75 | println!("{}/{}", prefix, self); 76 | for entry in &self.entries { 77 | let entry_ref = (**entry).borrow(); 78 | entry_ref.print_line_with_prefix(&format!("{}/{}", prefix, self.name)) 79 | } 80 | } 81 | } 82 | 83 | impl Display for Directory { 84 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 85 | write!(f, "{} ({})", self.name, self.get_size()) 86 | } 87 | } 88 | 89 | impl Entry for Directory { 90 | fn get_name(&self) -> &str { 91 | &self.name 92 | } 93 | 94 | fn get_size(&self) -> usize { 95 | self.entries.iter().fold(0, |r, e| r + e.borrow().get_size()) 96 | } 97 | } 98 | 99 | #[cfg(test)] 100 | mod test { 101 | use std::cell::RefCell; 102 | 103 | use super::*; 104 | 105 | #[test] 106 | fn test() { 107 | let mut rootdir = Directory::new("root"); 108 | let bindir = Rc::new(RefCell::new(Directory::new("bin"))); 109 | let tmpdir = Rc::new(RefCell::new(Directory::new("tmp"))); 110 | let usrdir = Rc::new(RefCell::new(Directory::new("usr"))); 111 | 112 | rootdir.add(bindir.clone()); 113 | rootdir.add(tmpdir.clone()); 114 | rootdir.add(usrdir.clone()); 115 | 116 | { 117 | let mut bindir_ref = (&*bindir).borrow_mut(); 118 | bindir_ref.add(Rc::new(RefCell::new(File::new("vi", 10000)))); 119 | bindir_ref.add(Rc::new(RefCell::new(File::new("latex", 20000)))); 120 | // bindir_ref.print_line(); 121 | } 122 | 123 | let yuki = Rc::new(RefCell::new(Directory::new("yuki"))); 124 | let hanako = Rc::new(RefCell::new(Directory::new("hanako"))); 125 | let tomura = Rc::new(RefCell::new(Directory::new("tomura"))); 126 | 127 | { 128 | let mut usrdir_ref = (&*usrdir).borrow_mut(); 129 | usrdir_ref.add(yuki.clone()); 130 | usrdir_ref.add(hanako.clone()); 131 | usrdir_ref.add(tomura.clone()); 132 | // usrdir_ref.print_line(); 133 | } 134 | 135 | { 136 | let mut yuki_ref = (&*yuki).borrow_mut(); 137 | yuki_ref.add(Rc::new(RefCell::new(File::new("diary.html", 100)))); 138 | yuki_ref.add(Rc::new(RefCell::new(File::new("Composite.java", 200)))); 139 | // yuki_ref.print_line(); 140 | } 141 | 142 | { 143 | let mut hanako_ref = (&*hanako).borrow_mut(); 144 | hanako_ref.add(Rc::new(RefCell::new(File::new("memo.tex", 300)))); 145 | // hanako_ref.print_line(); 146 | } 147 | 148 | { 149 | let mut tomura_ref = (&*tomura).borrow_mut(); 150 | tomura_ref.add(Rc::new(RefCell::new(File::new("game.doc", 400)))); 151 | tomura_ref.add(Rc::new(RefCell::new(File::new("junk.mail", 500)))); 152 | // tomura_ref.print_line(); 153 | } 154 | 155 | rootdir.print_line(); 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/decorator.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod trait_base; 3 | -------------------------------------------------------------------------------- /src/decorator/enum_base.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | 3 | #[derive(Debug)] 4 | pub enum Display { 5 | String(String), 6 | SideBorder(Rc, char), 7 | FullBorder(Rc), 8 | } 9 | 10 | impl Display { 11 | fn make_line(ch: char, count: usize) -> String { 12 | let mut line = String::new(); 13 | for _ in 0..count { 14 | line.push(ch); 15 | } 16 | line 17 | } 18 | 19 | pub fn of_string(value: &str) -> Self { 20 | Display::String(value.to_owned()) 21 | } 22 | 23 | pub fn of_side_border(underlying: Rc, border_char: char) -> Self { 24 | Display::SideBorder(underlying, border_char) 25 | } 26 | 27 | pub fn of_full_border(underlying: Rc) -> Self { 28 | Display::FullBorder(underlying) 29 | } 30 | 31 | pub fn get_columns(&self) -> usize { 32 | match self { 33 | Display::String(value) => value.len(), 34 | Display::SideBorder(underlying, ..) => 1 + underlying.get_columns() + 1, 35 | Display::FullBorder(underlying) => 1 + underlying.get_columns() + 1, 36 | } 37 | } 38 | 39 | pub fn get_rows(&self) -> u32 { 40 | match self { 41 | Display::String(value) => 1, 42 | Display::SideBorder(underlying, ..) => underlying.get_rows(), 43 | Display::FullBorder(underlying) => 1 + underlying.get_rows() + 1, 44 | } 45 | } 46 | 47 | pub fn get_row_text(&self, row: u32) -> String { 48 | match self { 49 | Display::String(value) => { 50 | if row != 0 { 51 | panic!("index of bounds"); 52 | } 53 | value.clone() 54 | } 55 | Display::SideBorder(underlying, border_char) => { 56 | format!("{}{}{}", border_char, underlying.get_row_text(row), border_char) 57 | } 58 | Display::FullBorder(underlying) => { 59 | if row == 0 { 60 | format!("+{}+", Self::make_line('-', underlying.get_columns())) 61 | } else if row == underlying.get_rows() + 1 { 62 | format!("+{}+", Self::make_line('-', underlying.get_columns())) 63 | } else { 64 | format!("|{}|", underlying.get_row_text(row - 1)) 65 | } 66 | } 67 | } 68 | } 69 | 70 | pub fn show(&self) { 71 | for i in 0..self.get_rows() { 72 | let s = self.get_row_text(i); 73 | println!("{}", s) 74 | } 75 | } 76 | } 77 | 78 | #[cfg(test)] 79 | mod test { 80 | use super::*; 81 | 82 | #[test] 83 | fn test() { 84 | let b1 = Rc::new(Display::of_string("Hello, world.")); 85 | let b2 = Rc::new(Display::of_side_border(b1.clone(), '#')); 86 | let b3 = Display::of_full_border(b2.clone()); 87 | b1.show(); 88 | b2.show(); 89 | b3.show(); 90 | let b4 = Display::of_side_border( 91 | Rc::new(Display::of_full_border(Rc::new(Display::of_full_border(Rc::new( 92 | Display::of_side_border( 93 | Rc::new(Display::of_full_border(Rc::new(Display::of_string("Hello, world.")))), 94 | '*', 95 | ), 96 | ))))), 97 | '/', 98 | ); 99 | b4.show(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/decorator/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::rc::Rc; 3 | 4 | pub trait Display: Debug { 5 | fn get_columns(&self) -> usize; 6 | fn get_rows(&self) -> u32; 7 | fn get_row_text(&self, row: u32) -> String; 8 | 9 | fn show(&self) { 10 | for i in 0..self.get_rows() { 11 | let s = self.get_row_text(i); 12 | println!("{}", s) 13 | } 14 | } 15 | } 16 | 17 | #[derive(Debug)] 18 | pub struct StringDisplay(String); 19 | 20 | impl StringDisplay { 21 | pub fn new(s: &str) -> Self { 22 | Self(s.to_owned()) 23 | } 24 | } 25 | 26 | impl Display for StringDisplay { 27 | fn get_columns(&self) -> usize { 28 | self.0.len() 29 | } 30 | 31 | fn get_rows(&self) -> u32 { 32 | 1 33 | } 34 | 35 | fn get_row_text(&self, row: u32) -> String { 36 | if row != 0 { 37 | panic!("index of bounds"); 38 | } 39 | self.0.clone() 40 | } 41 | } 42 | 43 | pub trait Border: Display {} 44 | 45 | #[derive(Debug)] 46 | pub struct FullBorder { 47 | underlying: Rc, 48 | } 49 | 50 | impl FullBorder { 51 | pub fn new(underlying: Rc) -> Self { 52 | Self { underlying } 53 | } 54 | 55 | fn make_line(ch: char, count: usize) -> String { 56 | let mut line = String::new(); 57 | for _ in 0..count { 58 | line.push(ch); 59 | } 60 | line 61 | } 62 | } 63 | 64 | impl Display for FullBorder { 65 | fn get_columns(&self) -> usize { 66 | 1 + self.underlying.get_columns() + 1 67 | } 68 | 69 | fn get_rows(&self) -> u32 { 70 | 1 + self.underlying.get_rows() + 1 71 | } 72 | 73 | fn get_row_text(&self, row: u32) -> String { 74 | if row == 0 { 75 | format!("+{}+", FullBorder::make_line('-', self.underlying.get_columns())) 76 | } else if row == self.underlying.get_rows() + 1 { 77 | format!("+{}+", FullBorder::make_line('-', self.underlying.get_columns())) 78 | } else { 79 | format!("|{}|", self.underlying.get_row_text(row - 1)) 80 | } 81 | } 82 | } 83 | 84 | #[derive(Debug)] 85 | pub struct SideBorder { 86 | underlying: Rc, 87 | border_char: char, 88 | } 89 | 90 | impl SideBorder { 91 | pub fn new(underlying: Rc, ch: char) -> Self { 92 | Self { 93 | underlying, 94 | border_char: ch, 95 | } 96 | } 97 | } 98 | 99 | impl Display for SideBorder { 100 | fn get_columns(&self) -> usize { 101 | 1 + self.underlying.get_columns() + 1 102 | } 103 | 104 | fn get_rows(&self) -> u32 { 105 | self.underlying.get_rows() 106 | } 107 | 108 | fn get_row_text(&self, row: u32) -> String { 109 | format!( 110 | "{}{}{}", 111 | self.border_char, 112 | self.underlying.get_row_text(row), 113 | self.border_char 114 | ) 115 | } 116 | } 117 | 118 | #[cfg(test)] 119 | mod test { 120 | use super::*; 121 | 122 | #[test] 123 | fn test() { 124 | let b1 = Rc::new(StringDisplay::new("Hello, world.")); 125 | let b2 = Rc::new(SideBorder::new(b1.clone(), '#')); 126 | let b3 = FullBorder::new(b2.clone()); 127 | b1.show(); 128 | b2.show(); 129 | b3.show(); 130 | let b4 = SideBorder::new( 131 | Rc::new(FullBorder::new(Rc::new(FullBorder::new(Rc::new(SideBorder::new( 132 | Rc::new(FullBorder::new(Rc::new(StringDisplay::new("Hello, world.")))), 133 | '*', 134 | )))))), 135 | '/', 136 | ); 137 | b4.show(); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/factory_method.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter}; 2 | use std::rc::Rc; 3 | 4 | pub trait Product: Display { 5 | fn r#use(&self); 6 | } 7 | 8 | trait FactoryBase { 9 | fn create_product(&self, owner: &str) -> Rc; 10 | fn register_product(&mut self, product: Rc); 11 | } 12 | 13 | pub trait Factory: FactoryBase { 14 | fn create(&mut self, owner: &str) -> Rc { 15 | let p = self.create_product(owner); 16 | self.register_product(p.clone()); 17 | p 18 | } 19 | } 20 | 21 | #[derive(Debug)] 22 | pub struct IdCard { 23 | owner: String, 24 | } 25 | 26 | impl IdCard { 27 | pub fn new(owner: &str) -> Self { 28 | println!("{}のカードを作ります", owner); 29 | Self { 30 | owner: owner.to_owned(), 31 | } 32 | } 33 | 34 | pub fn owner(&self) -> &str { 35 | &self.owner 36 | } 37 | } 38 | 39 | impl Display for IdCard { 40 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 41 | write!(f, "[IdCard:{}]", self.owner) 42 | } 43 | } 44 | 45 | impl Product for IdCard { 46 | fn r#use(&self) { 47 | println!("{}を使います", self.owner) 48 | } 49 | } 50 | 51 | #[derive(Debug)] 52 | pub struct IdCardFactory; 53 | 54 | impl IdCardFactory { 55 | pub fn new() -> Self { 56 | Self 57 | } 58 | } 59 | 60 | impl FactoryBase for IdCardFactory { 61 | fn create_product(&self, owner: &str) -> Rc { 62 | Rc::new(IdCard::new(owner)) 63 | } 64 | 65 | fn register_product(&mut self, product: Rc) { 66 | println!("{}を登録しました", product) 67 | } 68 | } 69 | 70 | impl Factory for IdCardFactory {} 71 | 72 | #[cfg(test)] 73 | mod test { 74 | use super::*; 75 | 76 | #[test] 77 | fn test() { 78 | let mut factory = IdCardFactory::new(); 79 | let card1 = factory.create("Hiroshi Yuki"); 80 | let card2 = factory.create("Tomura"); 81 | let card3 = factory.create("Hanako Sato"); 82 | card1.r#use(); 83 | card2.r#use(); 84 | card3.r#use(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/flyweight.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fmt::{Display, Formatter}; 3 | use std::fs::File; 4 | use std::io::{BufRead, BufReader}; 5 | use std::rc::Rc; 6 | use std::sync::Mutex; 7 | 8 | use anyhow::Result; 9 | use once_cell::sync::OnceCell; 10 | 11 | #[derive(Debug)] 12 | pub struct BigChar { 13 | char_name: char, 14 | font_data: String, 15 | } 16 | 17 | unsafe impl Send for BigChar {} 18 | 19 | impl Display for BigChar { 20 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 21 | write!(f, "{}", self.font_data) 22 | } 23 | } 24 | 25 | impl BigChar { 26 | fn read_font_data(char_name: char) -> Result { 27 | println!("read_font_data: {}", char_name); 28 | let file_name = format!("flyweight/big{}.txt", char_name); 29 | let mut reader = BufReader::new(File::open(file_name)?); 30 | let mut line: String = String::new(); 31 | let mut buf = String::new(); 32 | while let Ok(size) = reader.read_line(&mut line) { 33 | if size == 0 { 34 | break; 35 | } 36 | buf.push_str(&line); 37 | line.clear(); 38 | } 39 | Ok(buf.to_string()) 40 | } 41 | 42 | pub fn new(char_name: char) -> Self { 43 | let font_data = Self::read_font_data(char_name).unwrap(); 44 | Self { char_name, font_data } 45 | } 46 | } 47 | 48 | #[derive(Debug)] 49 | pub struct BigCharFactory { 50 | pool: HashMap>, 51 | } 52 | 53 | unsafe impl Send for BigCharFactory {} 54 | 55 | impl BigCharFactory { 56 | pub fn new() -> Self { 57 | Self { pool: HashMap::new() } 58 | } 59 | 60 | pub fn get_big_char(&mut self, char_name: char) -> Rc { 61 | let result = self 62 | .pool 63 | .entry(char_name) 64 | .or_insert_with(|| Rc::new(BigChar::new(char_name))); 65 | result.clone() 66 | } 67 | } 68 | 69 | pub static BIG_CHAR_FACTORY_SINGLETON: OnceCell> = OnceCell::new(); 70 | 71 | #[derive(Debug)] 72 | pub struct BigString { 73 | big_chars: Vec>, 74 | } 75 | 76 | impl Display for BigString { 77 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 78 | let mut buf = String::new(); 79 | for bc in &self.big_chars { 80 | buf = format!("{}{}", buf, bc); 81 | } 82 | write!(f, "{}", buf) 83 | } 84 | } 85 | 86 | impl BigString { 87 | pub fn new(string: &str) -> Self { 88 | let mut big_chars = Vec::with_capacity(string.len()); 89 | let factory = BIG_CHAR_FACTORY_SINGLETON.get_or_init(|| Mutex::new(BigCharFactory::new())); 90 | for (i, c) in string.chars().enumerate() { 91 | let mut f = factory.lock().unwrap(); 92 | let bc = f.get_big_char(c); 93 | big_chars.insert(i, bc); 94 | } 95 | Self { big_chars } 96 | } 97 | } 98 | 99 | #[cfg(test)] 100 | mod test { 101 | use super::*; 102 | 103 | #[test] 104 | fn test() { 105 | let bs = BigString::new("1928374650564738291"); 106 | print!("{}", bs); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/iterator.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone)] 2 | pub struct Book { 3 | name: String, 4 | } 5 | 6 | impl Book { 7 | pub fn new(name: &str) -> Self { 8 | Self { name: name.to_owned() } 9 | } 10 | 11 | pub fn name(&self) -> &str { 12 | &self.name 13 | } 14 | } 15 | 16 | #[derive(Debug)] 17 | pub struct BookShelf { 18 | values: Vec, 19 | last: usize, 20 | } 21 | 22 | impl BookShelf { 23 | pub fn new(capacity: usize) -> Self { 24 | Self { 25 | values: Vec::with_capacity(capacity), 26 | last: 0, 27 | } 28 | } 29 | 30 | pub fn with_elements(values: &[Book]) -> Self { 31 | Self { 32 | values: values.to_vec(), 33 | last: 0, 34 | } 35 | } 36 | 37 | pub fn get_book_at(&self, index: usize) -> &Book { 38 | &self.values[index] 39 | } 40 | 41 | pub fn append_book(&mut self, book: Book) { 42 | self.values.push(book); 43 | self.last += 1; 44 | } 45 | 46 | pub fn get_length(&self) -> usize { 47 | self.last 48 | } 49 | 50 | pub fn iter(&self) -> BookShelfIterator { 51 | BookShelfIterator::new(self) 52 | } 53 | } 54 | 55 | pub struct BookShelfIterator<'a> { 56 | book_shelf: &'a BookShelf, 57 | index: usize, 58 | } 59 | 60 | impl<'a> BookShelfIterator<'a> { 61 | pub fn new(book_shelf: &'a BookShelf) -> Self { 62 | Self { book_shelf, index: 0 } 63 | } 64 | } 65 | 66 | impl<'a> Iterator for BookShelfIterator<'a> { 67 | type Item = &'a Book; 68 | 69 | fn next(&mut self) -> Option { 70 | match self.index < self.book_shelf.values.len() { 71 | true => { 72 | let t = Some(&self.book_shelf.values[self.index]); 73 | self.index += 1; 74 | t 75 | } 76 | false => None, 77 | } 78 | } 79 | } 80 | 81 | impl<'a> IntoIterator for &'a BookShelf { 82 | type IntoIter = BookShelfIterator<'a>; 83 | type Item = &'a Book; 84 | 85 | fn into_iter(self) -> Self::IntoIter { 86 | self.iter() 87 | } 88 | } 89 | 90 | #[cfg(test)] 91 | mod test { 92 | use super::*; 93 | 94 | #[test] 95 | fn test() { 96 | let mut book_shelf = BookShelf::new(4); 97 | book_shelf.append_book(Book::new("Around the World in 80 Days")); 98 | book_shelf.append_book(Book::new("Bible")); 99 | book_shelf.append_book(Book::new("Cinderella")); 100 | book_shelf.append_book(Book::new("Daddy-Long-Legs")); 101 | 102 | // Iteratorの実装によって可能になる 103 | let mut it = book_shelf.iter(); 104 | while let Some(book) = it.next() { 105 | println!("{}", book.name()) 106 | } 107 | 108 | // IntoIteratorの実装によって可能になる 109 | for book in &book_shelf { 110 | println!("{}", book.name()) 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | // #![feature(min_type_alias_impl_trait)] 2 | #![feature(type_alias_impl_trait)] 3 | // #![feature(generic_associated_types)] 4 | extern crate chrono; 5 | extern crate core; 6 | extern crate timer; 7 | 8 | mod adaptor; 9 | mod bridge; 10 | mod builder; 11 | mod chain_of_responsibility; 12 | mod command; 13 | mod composite; 14 | mod decorator; 15 | mod factory_method; 16 | mod flyweight; 17 | mod iterator; 18 | mod mediator; 19 | mod observer; 20 | mod proxy; 21 | mod singleton; 22 | mod state; 23 | mod strategy; 24 | mod template_method_new; 25 | mod template_method_old; 26 | mod visitor; 27 | 28 | fn main() {} 29 | -------------------------------------------------------------------------------- /src/mediator.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::BorrowMut; 2 | use std::cell::RefCell; 3 | use std::collections::HashMap; 4 | use std::rc::Rc; 5 | 6 | pub trait Colleague { 7 | fn name(&self) -> &str; 8 | fn on_changed(&mut self, msg: &str); 9 | fn run(&self); 10 | } 11 | 12 | pub trait Mediator { 13 | fn add_colleague(&mut self, colleague: Rc>); 14 | fn colleague_changed(&mut self, colleague_updated: &dyn Colleague, msg: &str); 15 | } 16 | 17 | pub struct ConcreteMediator { 18 | colleagues: HashMap>>, 19 | } 20 | 21 | impl ConcreteMediator { 22 | pub fn new() -> Self { 23 | Self { 24 | colleagues: HashMap::new(), 25 | } 26 | } 27 | } 28 | 29 | impl Mediator for ConcreteMediator { 30 | fn add_colleague(&mut self, colleague: Rc>) { 31 | let colleague_cloned = colleague.clone(); 32 | let cr = colleague.borrow(); 33 | self.colleagues.insert(cr.name().to_owned(), colleague_cloned); 34 | } 35 | 36 | fn colleague_changed(&mut self, colleague: &dyn Colleague, msg: &str) { 37 | self.colleagues.iter().for_each(|(k, v)| { 38 | if k != colleague.name() { 39 | (**v).borrow_mut().on_changed(msg); 40 | } 41 | }); 42 | } 43 | } 44 | 45 | pub struct ConcreteColleagueA { 46 | mediator: Rc>, 47 | name: String, 48 | } 49 | 50 | impl ConcreteColleagueA { 51 | pub fn new(mediator: Rc>, name: &str) -> ConcreteColleagueA { 52 | Self { 53 | mediator, 54 | name: name.to_owned(), 55 | } 56 | } 57 | } 58 | 59 | impl Colleague for ConcreteColleagueA { 60 | fn name(&self) -> &str { 61 | &self.name 62 | } 63 | 64 | fn on_changed(&mut self, msg: &str) { 65 | println!("{} received: {}", self.name, msg); 66 | } 67 | 68 | fn run(&self) { 69 | let mut mr = (*self.mediator).borrow_mut(); 70 | mr.colleague_changed(self, "Hello"); 71 | } 72 | } 73 | 74 | pub struct ConcreteColleagueB { 75 | mediator: Rc>, 76 | name: String, 77 | } 78 | 79 | impl ConcreteColleagueB { 80 | pub fn new(mediator: Rc>, name: &str) -> Self { 81 | Self { 82 | mediator, 83 | name: name.to_owned(), 84 | } 85 | } 86 | } 87 | 88 | impl Colleague for ConcreteColleagueB { 89 | fn name(&self) -> &str { 90 | &self.name 91 | } 92 | 93 | fn on_changed(&mut self, msg: &str) { 94 | println!("{} received: {}", self.name, msg); 95 | } 96 | 97 | fn run(&self) { 98 | let mut mr = (*self.mediator).borrow_mut(); 99 | mr.colleague_changed(self, "Hi"); 100 | } 101 | } 102 | 103 | #[cfg(test)] 104 | mod test { 105 | use super::*; 106 | 107 | #[test] 108 | fn test() { 109 | let mediator = Rc::new(RefCell::new(ConcreteMediator::new())); 110 | let colleague_a = Rc::new(RefCell::new(ConcreteColleagueA::new(mediator.clone(), "A"))); 111 | let colleague_b = Rc::new(RefCell::new(ConcreteColleagueB::new(mediator.clone(), "B"))); 112 | 113 | (&*mediator).borrow_mut().add_colleague(colleague_a.clone()); 114 | (&*mediator).borrow_mut().add_colleague(colleague_b.clone()); 115 | 116 | (&*colleague_a).borrow().run(); 117 | (&*colleague_b).borrow().run(); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/observer.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod trait_base; 3 | -------------------------------------------------------------------------------- /src/observer/enum_base.rs: -------------------------------------------------------------------------------- 1 | use rand::prelude::ThreadRng; 2 | use rand::Rng; 3 | use std::borrow::Borrow; 4 | use std::cell::RefCell; 5 | use std::fmt::Debug; 6 | use std::rc::Rc; 7 | use std::{thread, time}; 8 | 9 | pub enum NumberGenerator { 10 | RandomNumber(RandomNumberNumberGenerator), 11 | } 12 | 13 | impl NumberGenerator { 14 | pub fn of_random() -> Self { 15 | NumberGenerator::RandomNumber(RandomNumberNumberGenerator::new()) 16 | } 17 | 18 | pub fn get_number(&self) -> u32 { 19 | match self { 20 | NumberGenerator::RandomNumber(g) => g.get_number(), 21 | _ => panic!(), 22 | } 23 | } 24 | 25 | pub fn add_observer(&mut self, observer: Observer) { 26 | match self { 27 | NumberGenerator::RandomNumber(g) => g.add_observer(observer), 28 | _ => panic!(), 29 | } 30 | } 31 | 32 | pub fn execute(&mut self) { 33 | match self { 34 | NumberGenerator::RandomNumber(g) => g.execute(), 35 | _ => panic!(), 36 | } 37 | } 38 | } 39 | 40 | #[derive(Clone)] 41 | pub struct RandomNumberNumberGenerator { 42 | inner: Rc>, 43 | } 44 | 45 | struct RandomNumberNumberGeneratorInner { 46 | observers: Vec, 47 | rng: ThreadRng, 48 | number: u32, 49 | } 50 | 51 | impl RandomNumberNumberGenerator { 52 | pub fn new() -> Self { 53 | Self { 54 | inner: Rc::new(RefCell::new(RandomNumberNumberGeneratorInner { 55 | observers: vec![], 56 | rng: rand::thread_rng(), 57 | number: 0, 58 | })), 59 | } 60 | } 61 | 62 | fn add_observer(&mut self, observer: Observer) { 63 | let mut g = (*self.inner).borrow_mut(); 64 | g.observers.push(observer); 65 | } 66 | 67 | fn delete_observer(&mut self, observer: &Observer) { 68 | let mut g = (*self.inner).borrow_mut(); 69 | let index = g 70 | .observers 71 | .iter() 72 | .position(|e| { 73 | let p1: *const Observer = e; 74 | let p2: *const Observer = observer; 75 | p1 == p2 76 | }) 77 | .unwrap(); 78 | g.observers.remove(index); 79 | } 80 | 81 | fn notify_observers(&self) { 82 | let g = (*self.inner).borrow(); 83 | for o in &g.observers { 84 | let p = NumberGenerator::RandomNumber(self.clone()); 85 | o.update(&p); 86 | } 87 | } 88 | 89 | fn get_number(&self) -> u32 { 90 | let g = (*self.inner).borrow(); 91 | g.number 92 | } 93 | 94 | fn execute(&mut self) { 95 | for _ in 0..20 { 96 | let mut g = (*self.inner).borrow_mut(); 97 | g.number = g.rng.gen_range(0..=49); 98 | drop(g); 99 | self.notify_observers(); 100 | } 101 | } 102 | } 103 | 104 | pub trait AnyObserver: Debug { 105 | fn update(&self, generator: &NumberGenerator); 106 | } 107 | 108 | #[derive(Clone)] 109 | pub enum Observer { 110 | Digit, 111 | Graph, 112 | Any(Rc), 113 | } 114 | 115 | impl Observer { 116 | pub fn update(&self, generator: &NumberGenerator) { 117 | match self { 118 | Observer::Digit => { 119 | println!("DigitObserver:{}", generator.get_number()); 120 | thread::sleep(time::Duration::from_millis(100)); 121 | } 122 | Observer::Graph => { 123 | print!("GraphObserver:"); 124 | let count = generator.get_number(); 125 | for _ in 0..count { 126 | print!("*"); 127 | } 128 | println!(); 129 | thread::sleep(time::Duration::from_millis(100)); 130 | } 131 | Observer::Any(rc) => rc.update(generator), 132 | } 133 | } 134 | } 135 | #[cfg(test)] 136 | mod test { 137 | use super::*; 138 | 139 | #[test] 140 | fn test() { 141 | let mut generator = NumberGenerator::of_random(); 142 | let observer1 = Observer::Digit; 143 | let observer2 = Observer::Graph; 144 | generator.add_observer(observer1); 145 | generator.add_observer(observer2); 146 | generator.execute(); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/observer/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | use std::{thread, time}; 3 | 4 | use rand::prelude::ThreadRng; 5 | use rand::Rng; 6 | 7 | pub trait NumberGenerator { 8 | fn add_observer(&mut self, observer: Box); 9 | fn delete_observer(&mut self, observer: Box); 10 | fn notify_observers(&self); 11 | fn get_number(&self) -> u32; 12 | fn execute(&mut self); 13 | } 14 | 15 | #[derive(Debug)] 16 | pub struct RandomNumberGenerator { 17 | observers: Vec>, 18 | rng: ThreadRng, 19 | number: u32, 20 | } 21 | 22 | impl RandomNumberGenerator { 23 | pub fn new() -> Self { 24 | Self { 25 | observers: Vec::new(), 26 | rng: rand::thread_rng(), 27 | number: 0, 28 | } 29 | } 30 | } 31 | 32 | impl NumberGenerator for RandomNumberGenerator { 33 | fn add_observer(&mut self, observer: Box) { 34 | self.observers.push(observer); 35 | } 36 | 37 | fn delete_observer(&mut self, observer: Box) { 38 | let index = self 39 | .observers 40 | .iter() 41 | .position(|e| { 42 | let p1: *const dyn Observer = &**e; 43 | let p2: *const dyn Observer = &*observer; 44 | std::ptr::addr_eq(p1, p2) 45 | }) 46 | .unwrap(); 47 | self.observers.remove(index); 48 | } 49 | 50 | fn notify_observers(&self) { 51 | for o in &self.observers { 52 | o.update(self) 53 | } 54 | } 55 | 56 | fn get_number(&self) -> u32 { 57 | self.number 58 | } 59 | 60 | fn execute(&mut self) { 61 | for _ in 0..20 { 62 | self.number = self.rng.gen_range(0..=49); 63 | self.notify_observers(); 64 | } 65 | } 66 | } 67 | 68 | pub trait Observer: Debug { 69 | fn update(&self, generator: &dyn NumberGenerator); 70 | } 71 | 72 | #[derive(Debug)] 73 | pub struct DigitObserver; 74 | 75 | impl DigitObserver { 76 | pub fn new() -> Self { 77 | Self 78 | } 79 | } 80 | 81 | impl Observer for DigitObserver { 82 | fn update(&self, generator: &dyn NumberGenerator) { 83 | println!("DigitObserver:{}", generator.get_number()); 84 | thread::sleep(time::Duration::from_millis(100)); 85 | } 86 | } 87 | 88 | #[derive(Debug)] 89 | pub struct GraphObserver; 90 | 91 | impl GraphObserver { 92 | pub fn new() -> Self { 93 | Self 94 | } 95 | } 96 | 97 | impl Observer for GraphObserver { 98 | fn update(&self, generator: &dyn NumberGenerator) { 99 | print!("GraphObserver:"); 100 | let count = generator.get_number(); 101 | for _ in 0..count { 102 | print!("*"); 103 | } 104 | println!(); 105 | thread::sleep(time::Duration::from_millis(100)); 106 | } 107 | } 108 | 109 | #[cfg(test)] 110 | mod test { 111 | use super::*; 112 | 113 | #[test] 114 | fn test() { 115 | let mut generator = RandomNumberGenerator::new(); 116 | let observer1 = DigitObserver::new(); 117 | let observer2 = GraphObserver::new(); 118 | generator.add_observer(Box::new(observer1)); 119 | generator.add_observer(Box::new(observer2)); 120 | generator.execute(); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/proxy.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod trait_base; 3 | -------------------------------------------------------------------------------- /src/proxy/enum_base.rs: -------------------------------------------------------------------------------- 1 | use std::{thread, time}; 2 | 3 | pub trait PrintableBehavior { 4 | fn set_printer_name(&mut self, name: &str); 5 | fn get_printer_name(&self) -> &str; 6 | fn print(&mut self, text: &str); 7 | } 8 | 9 | pub enum Printable { 10 | Printer(Printer), 11 | PrinterProxy(PrinterProxy), 12 | } 13 | 14 | impl Printable { 15 | pub fn of_printer(name: &str) -> Self { 16 | Printable::Printer(Printer::new(name)) 17 | } 18 | 19 | pub fn of_printer_proxy(name: &str) -> Self { 20 | Printable::PrinterProxy(PrinterProxy::new(name)) 21 | } 22 | } 23 | 24 | impl PrintableBehavior for Printable { 25 | fn set_printer_name(&mut self, name: &str) { 26 | match self { 27 | Printable::Printer(u) => u.set_printer_name(name), 28 | Printable::PrinterProxy(u) => u.set_printer_name(name), 29 | } 30 | } 31 | 32 | fn get_printer_name(&self) -> &str { 33 | match self { 34 | Printable::Printer(u) => u.get_printer_name(), 35 | Printable::PrinterProxy(u) => u.get_printer_name(), 36 | } 37 | } 38 | 39 | fn print(&mut self, text: &str) { 40 | match self { 41 | Printable::Printer(u) => u.print(text), 42 | Printable::PrinterProxy(u) => u.print(text), 43 | } 44 | } 45 | } 46 | 47 | #[derive(Debug)] 48 | pub struct Printer { 49 | name: String, 50 | } 51 | 52 | impl Printer { 53 | fn heavy_job(msg: &str) { 54 | print!("{}", msg); 55 | for i in 0..5 { 56 | thread::sleep(time::Duration::from_millis(1000)); 57 | println!("."); 58 | } 59 | println!("完了。"); 60 | } 61 | 62 | pub fn new(name: &str) -> Self { 63 | Self::heavy_job(&format!("Printerのインスタンス({})を生成中", name)); 64 | Self { name: name.to_owned() } 65 | } 66 | } 67 | 68 | impl PrintableBehavior for Printer { 69 | fn set_printer_name(&mut self, name: &str) { 70 | self.name = name.to_owned(); 71 | } 72 | 73 | fn get_printer_name(&self) -> &str { 74 | &self.name 75 | } 76 | 77 | fn print(&mut self, text: &str) { 78 | println!("=== {} ===", self.name); 79 | println!("{}", text); 80 | } 81 | } 82 | 83 | #[derive(Debug)] 84 | pub struct PrinterProxy { 85 | name: String, 86 | underlying: Option, 87 | } 88 | 89 | impl PrinterProxy { 90 | pub fn new(name: &str) -> Self { 91 | Self { 92 | name: name.to_owned(), 93 | underlying: None, 94 | } 95 | } 96 | 97 | fn realize(&mut self) { 98 | if self.underlying.is_none() { 99 | self.underlying = Some(Printer::new(&self.name)) 100 | } 101 | } 102 | } 103 | 104 | impl PrintableBehavior for PrinterProxy { 105 | fn set_printer_name(&mut self, name: &str) { 106 | if self.underlying.is_some() { 107 | self.underlying.as_mut().unwrap().set_printer_name(name); 108 | } 109 | self.name = name.to_owned(); 110 | } 111 | 112 | fn get_printer_name(&self) -> &str { 113 | &self.name 114 | } 115 | 116 | fn print(&mut self, text: &str) { 117 | self.realize(); 118 | self.underlying.as_mut().unwrap().print(text); 119 | } 120 | } 121 | 122 | #[cfg(test)] 123 | mod test { 124 | use super::*; 125 | 126 | #[test] 127 | fn test() { 128 | let mut proxy = Printable::of_printer_proxy("Alice"); 129 | fn process(p: &mut Printable) { 130 | println!("名前は現在{}です。", p.get_printer_name()); 131 | p.set_printer_name("Blob"); 132 | println!("名前は現在{}です。", p.get_printer_name()); 133 | p.print("Hello, world."); 134 | } 135 | process(&mut proxy); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/proxy/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::{thread, time}; 2 | 3 | pub trait Printable { 4 | fn set_printer_name(&mut self, name: &str); 5 | fn get_printer_name(&self) -> &str; 6 | fn print(&mut self, text: &str); 7 | } 8 | 9 | #[derive(Debug)] 10 | pub struct Printer { 11 | name: String, 12 | } 13 | 14 | impl Printer { 15 | fn heavy_job(msg: &str) { 16 | print!("{}", msg); 17 | for i in 0..5 { 18 | thread::sleep(time::Duration::from_millis(1000)); 19 | println!("."); 20 | } 21 | println!("完了。"); 22 | } 23 | 24 | pub fn new(name: &str) -> Self { 25 | Self::heavy_job(&format!("Printerのインスタンス({})を生成中", name)); 26 | Self { name: name.to_owned() } 27 | } 28 | } 29 | 30 | impl Printable for Printer { 31 | fn set_printer_name(&mut self, name: &str) { 32 | self.name = name.to_owned(); 33 | } 34 | 35 | fn get_printer_name(&self) -> &str { 36 | &self.name 37 | } 38 | 39 | fn print(&mut self, text: &str) { 40 | println!("=== {} ===", self.name); 41 | println!("{}", text); 42 | } 43 | } 44 | 45 | #[derive(Debug)] 46 | pub struct PrinterProxy { 47 | name: String, 48 | underlying: Option, 49 | } 50 | 51 | impl PrinterProxy { 52 | pub fn new(name: &str) -> Self { 53 | Self { 54 | name: name.to_owned(), 55 | underlying: None, 56 | } 57 | } 58 | 59 | fn realize(&mut self) { 60 | if self.underlying.is_none() { 61 | self.underlying = Some(Printer::new(&self.name)) 62 | } 63 | } 64 | } 65 | 66 | impl Printable for PrinterProxy { 67 | fn set_printer_name(&mut self, name: &str) { 68 | if self.underlying.is_some() { 69 | self.underlying.as_mut().unwrap().set_printer_name(name); 70 | } 71 | self.name = name.to_owned(); 72 | } 73 | 74 | fn get_printer_name(&self) -> &str { 75 | &self.name 76 | } 77 | 78 | fn print(&mut self, text: &str) { 79 | self.realize(); 80 | self.underlying.as_mut().unwrap().print(text); 81 | } 82 | } 83 | 84 | #[cfg(test)] 85 | mod test { 86 | use super::*; 87 | 88 | #[test] 89 | fn test() { 90 | let mut proxy = PrinterProxy::new("Alice"); 91 | fn process(p: &mut dyn Printable) { 92 | println!("名前は現在{}です。", p.get_printer_name()); 93 | p.set_printer_name("Blob"); 94 | println!("名前は現在{}です。", p.get_printer_name()); 95 | p.print("Hello, world."); 96 | } 97 | process(&mut proxy); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/singleton.rs: -------------------------------------------------------------------------------- 1 | use once_cell::sync::Lazy; 2 | use std::sync::Mutex; 3 | 4 | #[derive(Debug)] 5 | pub struct Singleton { 6 | name: String, 7 | } 8 | 9 | impl Singleton { 10 | pub fn name(&self) -> &str { 11 | &self.name 12 | } 13 | } 14 | 15 | pub static SINGLETON: Lazy = Lazy::new(|| Singleton { 16 | name: "TEST".to_owned(), 17 | }); 18 | 19 | pub static SINGLETON_MUT: Lazy> = Lazy::new(|| { 20 | Mutex::new(Singleton { 21 | name: "TEST".to_owned(), 22 | }) 23 | }); 24 | 25 | #[cfg(test)] 26 | mod test { 27 | use super::*; 28 | use std::borrow::Borrow; 29 | 30 | #[test] 31 | fn test() { 32 | let si = &SINGLETON.borrow(); 33 | let s = si.name(); 34 | println!("name = {}", s); 35 | } 36 | 37 | #[test] 38 | fn test_mut() { 39 | let si = &SINGLETON_MUT.lock().unwrap(); 40 | let s = si.name(); 41 | println!("name = {}", s); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/state.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod trait_base; 3 | -------------------------------------------------------------------------------- /src/state/enum_base.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter}; 2 | 3 | pub trait Context { 4 | fn change_state(&mut self, state: State); 5 | fn call_security_center(&self, msg: &str); 6 | fn record_log(&self, msg: &str); 7 | } 8 | 9 | #[derive(Debug, Clone, Copy, PartialEq)] 10 | pub enum State { 11 | Day, 12 | Night, 13 | } 14 | 15 | impl Display for State { 16 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 17 | match self { 18 | State::Night => write!(f, "[夜間]"), 19 | State::Day => write!(f, "[昼間]"), 20 | } 21 | } 22 | } 23 | 24 | impl State { 25 | pub fn do_clock(self, context: &mut impl Context, hour: u32) -> State { 26 | let new_state = match (self, (9..17).contains(&hour)) { 27 | (State::Night, true) | (State::Day, false) => self.opposite(), 28 | _ => self, 29 | }; 30 | if new_state != self { 31 | context.change_state(new_state); 32 | } 33 | context.record_log(&format!("時刻は{}時になりました。", hour)); 34 | context.record_log(&format!("現在の状態は{}です。", new_state)); 35 | new_state 36 | } 37 | 38 | pub fn do_use(self, context: &impl Context) { 39 | match self { 40 | State::Night => context.call_security_center("非常:夜間の金庫使用!"), 41 | State::Day => context.record_log("金庫使用(昼間)"), 42 | } 43 | } 44 | 45 | pub fn do_alarm(self, context: &impl Context) { 46 | let msg = match self { 47 | State::Night => "非常ベル(夜間)", 48 | State::Day => "非常ベル(昼間)", 49 | }; 50 | context.call_security_center(msg); 51 | } 52 | 53 | pub fn do_phone(self, context: &impl Context) { 54 | let msg = match self { 55 | State::Night => "夜間の通話録音", 56 | State::Day => "通常の通話(昼間)", 57 | }; 58 | context.record_log(msg); 59 | } 60 | 61 | fn opposite(self) -> Self { 62 | match self { 63 | State::Day => State::Night, 64 | State::Night => State::Day, 65 | } 66 | } 67 | } 68 | 69 | struct StateContext { 70 | state: State, 71 | } 72 | 73 | impl StateContext { 74 | fn new(state: State) -> Self { 75 | Self { state } 76 | } 77 | 78 | fn run(&mut self) { 79 | for hour in 0..=24 { 80 | self.state = self.state.do_clock(self, hour); 81 | match hour % 3 { 82 | 0 => self.state.do_use(self), 83 | 1 => self.state.do_alarm(self), 84 | 2 => self.state.do_phone(self), 85 | _ => unreachable!(), 86 | } 87 | } 88 | } 89 | } 90 | 91 | impl Context for StateContext { 92 | fn change_state(&mut self, state: State) { 93 | self.state = state; 94 | } 95 | 96 | fn call_security_center(&self, msg: &str) { 97 | println!("{}:{}", self.state, msg); 98 | } 99 | 100 | fn record_log(&self, msg: &str) { 101 | println!("{}:{}", self.state, msg); 102 | } 103 | } 104 | 105 | #[cfg(test)] 106 | mod test { 107 | use super::*; 108 | 109 | #[test] 110 | fn test() { 111 | let mut context = StateContext::new(State::Day); 112 | context.run(); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/state/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter}; 2 | 3 | pub trait Context { 4 | fn set_clock(&mut self, hour: u32); 5 | fn change_state(&mut self, state: &'static dyn State); 6 | fn call_security_center(&self, msg: &str); 7 | fn record_log(&self, msg: &str); 8 | } 9 | 10 | pub trait State: Display { 11 | fn do_clock(&self, context: &mut dyn Context, hour: u32); 12 | fn do_use(&self, context: &dyn Context); 13 | fn do_alarm(&self, context: &dyn Context); 14 | fn do_phone(&self, context: &dyn Context); 15 | } 16 | 17 | struct Day; 18 | 19 | impl Display for Day { 20 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 21 | write!(f, "[昼間]") 22 | } 23 | } 24 | 25 | impl State for Day { 26 | fn do_clock(&self, context: &mut dyn Context, hour: u32) { 27 | if !(9..17).contains(&hour) { 28 | context.change_state(&NIGHT); 29 | } 30 | } 31 | 32 | fn do_use(&self, context: &dyn Context) { 33 | context.record_log("金庫使用(昼間)"); 34 | } 35 | 36 | fn do_alarm(&self, context: &dyn Context) { 37 | context.call_security_center("非常ベル(昼間)"); 38 | } 39 | 40 | fn do_phone(&self, context: &dyn Context) { 41 | context.record_log("通常の通話(昼間)"); 42 | } 43 | } 44 | 45 | struct Night; 46 | 47 | impl Display for Night { 48 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 49 | write!(f, "[夜間]") 50 | } 51 | } 52 | 53 | impl State for Night { 54 | fn do_clock(&self, context: &mut dyn Context, hour: u32) { 55 | if (9..17).contains(&hour) { 56 | context.change_state(&DAY); 57 | } 58 | } 59 | 60 | fn do_use(&self, context: &dyn Context) { 61 | context.call_security_center("非常:夜間の金庫使用!"); 62 | } 63 | 64 | fn do_alarm(&self, context: &dyn Context) { 65 | context.call_security_center("非常ベル(夜間)"); 66 | } 67 | 68 | fn do_phone(&self, context: &dyn Context) { 69 | context.record_log("夜間の通話録音"); 70 | } 71 | } 72 | 73 | static DAY: Day = Day; 74 | static NIGHT: Night = Night; 75 | 76 | struct StateContext { 77 | state: &'static dyn State, 78 | } 79 | 80 | impl StateContext { 81 | fn new(state: &'static dyn State) -> Self { 82 | Self { state } 83 | } 84 | 85 | fn run(&mut self) { 86 | for hour in 0..=24 { 87 | self.set_clock(hour); 88 | match hour % 3 { 89 | 0 => self.state.do_use(self), 90 | 1 => self.state.do_alarm(self), 91 | 2 => self.state.do_phone(self), 92 | _ => unreachable!(), 93 | } 94 | } 95 | } 96 | } 97 | 98 | impl Context for StateContext { 99 | fn set_clock(&mut self, hour: u32) { 100 | self.state.do_clock(self, hour); 101 | } 102 | 103 | fn change_state(&mut self, state: &'static dyn State) { 104 | self.state = state; 105 | } 106 | 107 | fn call_security_center(&self, msg: &str) { 108 | println!("{}:{}", self.state, msg); 109 | } 110 | 111 | fn record_log(&self, msg: &str) { 112 | println!("{}:{}", self.state, msg); 113 | } 114 | } 115 | 116 | #[cfg(test)] 117 | mod test { 118 | use super::*; 119 | 120 | #[test] 121 | fn test() { 122 | let mut context = StateContext::new(&DAY); 123 | context.run(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/strategy.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::{Display, Formatter}; 2 | 3 | mod enum_base; 4 | mod trait_base; 5 | 6 | #[derive(Clone, Debug, PartialEq)] 7 | pub enum Hand { 8 | GUU, 9 | CHO, 10 | PAA, 11 | } 12 | 13 | impl Hand { 14 | pub fn name(&self) -> &str { 15 | match self { 16 | Hand::GUU => "グー", 17 | Hand::CHO => "チョキ", 18 | Hand::PAA => "パー", 19 | } 20 | } 21 | 22 | pub fn get_hand(value: u32) -> Self { 23 | match value { 24 | 0 => Hand::GUU, 25 | 1 => Hand::CHO, 26 | 2 => Hand::PAA, 27 | _ => panic!("not found"), 28 | } 29 | } 30 | 31 | fn hand_value(&self) -> i32 { 32 | match self { 33 | Hand::GUU => 0, 34 | Hand::CHO => 1, 35 | Hand::PAA => 2, 36 | } 37 | } 38 | 39 | fn fight(&self, h: Hand) -> i32 { 40 | if *self == h { 41 | 0 42 | } else if (self.hand_value() + 1) % 3 == h.hand_value() { 43 | 1 44 | } else { 45 | -1 46 | } 47 | } 48 | 49 | pub fn is_stronger_than(&self, h: Hand) -> bool { 50 | self.fight(h) == 1 51 | } 52 | 53 | pub fn is_weaker_than(&self, h: Hand) -> bool { 54 | self.fight(h) == -1 55 | } 56 | } 57 | 58 | impl Display for Hand { 59 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 60 | write!(f, "{}", self.name()) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/strategy/enum_base.rs: -------------------------------------------------------------------------------- 1 | use rand::prelude::*; 2 | use std::fmt::{Display, Formatter}; 3 | 4 | #[derive(Debug, Clone, Copy)] 5 | pub enum Hand { 6 | Rock, 7 | Paper, 8 | Scissors, 9 | } 10 | 11 | impl Hand { 12 | fn get_hand(value: u8) -> Self { 13 | match value { 14 | 0 => Hand::Rock, 15 | 1 => Hand::Paper, 16 | _ => Hand::Scissors, 17 | } 18 | } 19 | 20 | fn is_stronger_than(&self, other: Hand) -> bool { 21 | matches!( 22 | (self, other), 23 | (Hand::Rock, Hand::Scissors) | (Hand::Scissors, Hand::Paper) | (Hand::Paper, Hand::Rock) 24 | ) 25 | } 26 | } 27 | 28 | #[derive(Debug)] 29 | pub enum Strategy { 30 | Winning { 31 | rng: ThreadRng, 32 | won: bool, 33 | prev_hand: Hand, 34 | }, 35 | Probe { 36 | rng: ThreadRng, 37 | prev_hand_value: u8, 38 | current_hand_value: u8, 39 | history: [[u32; 3]; 3], 40 | }, 41 | } 42 | 43 | impl Strategy { 44 | pub fn of_winning() -> Self { 45 | Strategy::Winning { 46 | rng: rand::thread_rng(), 47 | won: false, 48 | prev_hand: Hand::Rock, 49 | } 50 | } 51 | 52 | pub fn of_probe() -> Self { 53 | Strategy::Probe { 54 | rng: rand::thread_rng(), 55 | prev_hand_value: 0, 56 | current_hand_value: 0, 57 | history: [[1; 3]; 3], 58 | } 59 | } 60 | 61 | fn get_sum(history: &[[u32; 3]; 3], hand_value: u8) -> u32 { 62 | history[hand_value as usize].iter().sum() 63 | } 64 | 65 | pub fn next_hand(&mut self) -> Hand { 66 | match self { 67 | Strategy::Winning { rng, won, prev_hand } => { 68 | if !*won { 69 | *prev_hand = Hand::get_hand(rng.gen_range(0..=2)); 70 | } 71 | *prev_hand 72 | } 73 | Strategy::Probe { 74 | rng, 75 | prev_hand_value, 76 | current_hand_value, 77 | history, 78 | } => { 79 | let bet = rng.gen_range(0..=Self::get_sum(history, *current_hand_value)); 80 | let hand_value = if bet < history[*current_hand_value as usize][0] { 81 | 0 82 | } else if bet < history[*current_hand_value as usize][0] + history[*current_hand_value as usize][1] { 83 | 1 84 | } else { 85 | 2 86 | }; 87 | *prev_hand_value = *current_hand_value; 88 | *current_hand_value = hand_value; 89 | Hand::get_hand(hand_value) 90 | } 91 | } 92 | } 93 | 94 | pub fn study(&mut self, win: bool) { 95 | match self { 96 | Strategy::Winning { won, .. } => *won = win, 97 | Strategy::Probe { 98 | prev_hand_value, 99 | current_hand_value, 100 | history, 101 | .. 102 | } => { 103 | if win { 104 | history[*prev_hand_value as usize][*current_hand_value as usize] += 1; 105 | } else { 106 | history[*prev_hand_value as usize][((*current_hand_value + 1) % 3) as usize] += 1; 107 | history[*prev_hand_value as usize][((*current_hand_value + 2) % 3) as usize] += 1; 108 | } 109 | } 110 | } 111 | } 112 | } 113 | 114 | #[derive(Debug)] 115 | pub struct Player { 116 | name: String, 117 | strategy: Strategy, 118 | win_count: u32, 119 | lose_count: u32, 120 | game_count: u32, 121 | } 122 | 123 | impl Display for Player { 124 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 125 | write!( 126 | f, 127 | "[{}: {} games, {} win, {} lose]", 128 | self.name, self.game_count, self.win_count, self.lose_count 129 | ) 130 | } 131 | } 132 | 133 | impl Player { 134 | pub fn new(name: &str, strategy: Strategy) -> Self { 135 | Self { 136 | name: name.to_owned(), 137 | strategy, 138 | win_count: 0, 139 | lose_count: 0, 140 | game_count: 0, 141 | } 142 | } 143 | 144 | pub fn next_hand(&mut self) -> Hand { 145 | self.strategy.next_hand() 146 | } 147 | 148 | pub fn win(&mut self) { 149 | self.strategy.study(true); 150 | self.win_count += 1; 151 | self.game_count += 1; 152 | } 153 | 154 | pub fn lose(&mut self) { 155 | self.strategy.study(false); 156 | self.lose_count += 1; 157 | self.game_count += 1; 158 | } 159 | 160 | pub fn even(&mut self) { 161 | self.game_count += 1; 162 | } 163 | } 164 | 165 | #[cfg(test)] 166 | mod test { 167 | use super::*; 168 | 169 | #[test] 170 | fn test() { 171 | let mut player1 = Player::new("Taro", Strategy::of_winning()); 172 | let mut player2 = Player::new("Hana", Strategy::of_probe()); 173 | 174 | for _ in 0..10000 { 175 | let next_hand1 = player1.next_hand(); 176 | let next_hand2 = player2.next_hand(); 177 | if next_hand1.is_stronger_than(next_hand2) { 178 | println!("Winner:{}", player1); 179 | player1.win(); 180 | player2.lose(); 181 | } else if next_hand2.is_stronger_than(next_hand1) { 182 | println!("Winner:{}", player2); 183 | player1.lose(); 184 | player2.win(); 185 | } else { 186 | player1.even(); 187 | player2.even(); 188 | } 189 | } 190 | 191 | println!("Total result:"); 192 | println!("{}", player1); 193 | println!("{}", player2); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /src/strategy/trait_base.rs: -------------------------------------------------------------------------------- 1 | use rand::prelude::*; 2 | use rand::Rng; 3 | use std::fmt::{Display, Formatter}; 4 | 5 | #[derive(Clone, Copy, Debug)] 6 | pub enum Hand { 7 | Rock, 8 | Paper, 9 | Scissors, 10 | } 11 | 12 | impl Hand { 13 | fn get_hand(value: u8) -> Self { 14 | match value { 15 | 0 => Hand::Rock, 16 | 1 => Hand::Paper, 17 | _ => Hand::Scissors, 18 | } 19 | } 20 | 21 | fn is_stronger_than(&self, other: Hand) -> bool { 22 | matches!( 23 | (self, other), 24 | (Hand::Rock, Hand::Scissors) | (Hand::Scissors, Hand::Paper) | (Hand::Paper, Hand::Rock) 25 | ) 26 | } 27 | } 28 | 29 | pub trait Strategy { 30 | fn next_hand(&mut self) -> Hand; 31 | fn study(&mut self, win: bool); 32 | } 33 | 34 | #[derive(Clone, Debug)] 35 | pub struct WinningStrategy { 36 | rng: ThreadRng, 37 | won: bool, 38 | prev_hand: Hand, 39 | } 40 | 41 | impl Strategy for WinningStrategy { 42 | fn next_hand(&mut self) -> Hand { 43 | if !self.won { 44 | self.prev_hand = Hand::get_hand(self.rng.gen_range(0..=2)) 45 | } 46 | self.prev_hand 47 | } 48 | 49 | fn study(&mut self, win: bool) { 50 | self.won = win; 51 | } 52 | } 53 | 54 | impl WinningStrategy { 55 | pub fn new() -> Self { 56 | Self { 57 | rng: rand::thread_rng(), 58 | won: false, 59 | prev_hand: Hand::Rock, 60 | } 61 | } 62 | } 63 | 64 | #[derive(Clone, Debug)] 65 | pub struct ProbeStrategy { 66 | rng: ThreadRng, 67 | prev_hand_value: u8, 68 | current_hand_value: u8, 69 | history: [[u32; 3]; 3], 70 | } 71 | 72 | impl Strategy for ProbeStrategy { 73 | fn next_hand(&mut self) -> Hand { 74 | let bet = self.rng.gen_range(0..=self.get_sum(self.current_hand_value)); 75 | let hand_value = if bet < self.history[self.current_hand_value as usize][0] { 76 | 0 77 | } else if bet 78 | < self.history[self.current_hand_value as usize][0] + self.history[self.current_hand_value as usize][1] 79 | { 80 | 1 81 | } else { 82 | 2 83 | }; 84 | self.prev_hand_value = self.current_hand_value; 85 | self.current_hand_value = hand_value; 86 | Hand::get_hand(hand_value) 87 | } 88 | 89 | fn study(&mut self, win: bool) { 90 | if win { 91 | self.history[self.prev_hand_value as usize][self.current_hand_value as usize] += 1; 92 | } else { 93 | self.history[self.prev_hand_value as usize][((self.current_hand_value + 1) % 3) as usize] += 1; 94 | self.history[self.prev_hand_value as usize][((self.current_hand_value + 2) % 3) as usize] += 1; 95 | } 96 | } 97 | } 98 | 99 | impl ProbeStrategy { 100 | fn get_sum(&self, hand_value: u8) -> u32 { 101 | self.history[hand_value as usize].iter().sum() 102 | } 103 | 104 | pub fn new() -> Self { 105 | Self { 106 | rng: rand::thread_rng(), 107 | prev_hand_value: 0, 108 | current_hand_value: 0, 109 | history: [[1; 3]; 3], 110 | } 111 | } 112 | } 113 | 114 | pub struct Player { 115 | name: String, 116 | strategy: Box, 117 | win_count: u32, 118 | lose_count: u32, 119 | game_count: u32, 120 | } 121 | 122 | impl Display for Player { 123 | fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 124 | write!( 125 | f, 126 | "[{}: {} games, {} win, {} lose]", 127 | self.name, self.game_count, self.win_count, self.lose_count 128 | ) 129 | } 130 | } 131 | 132 | impl Player { 133 | pub fn new(name: &str, strategy: Box) -> Self { 134 | Self { 135 | name: name.to_owned(), 136 | strategy, 137 | win_count: 0, 138 | lose_count: 0, 139 | game_count: 0, 140 | } 141 | } 142 | 143 | pub fn next_hand(&mut self) -> Hand { 144 | self.strategy.next_hand() 145 | } 146 | 147 | pub fn win(&mut self) { 148 | self.strategy.study(true); 149 | self.win_count += 1; 150 | self.game_count += 1; 151 | } 152 | 153 | pub fn lose(&mut self) { 154 | self.strategy.study(false); 155 | self.lose_count += 1; 156 | self.game_count += 1; 157 | } 158 | 159 | pub fn even(&mut self) { 160 | self.game_count += 1; 161 | } 162 | } 163 | 164 | #[cfg(test)] 165 | mod test { 166 | use super::*; 167 | 168 | #[test] 169 | fn test() { 170 | let mut player1 = Player::new("Taro", Box::new(WinningStrategy::new())); 171 | let mut player2 = Player::new("Hana", Box::new(ProbeStrategy::new())); 172 | 173 | for _ in 0..10000 { 174 | let next_hand1 = player1.next_hand(); 175 | let next_hand2 = player2.next_hand(); 176 | if next_hand1.is_stronger_than(next_hand2) { 177 | println!("Winner:{}", player1); 178 | player1.win(); 179 | player2.lose(); 180 | } else if next_hand2.is_stronger_than(next_hand1) { 181 | println!("Winner:{}", player2); 182 | player1.lose(); 183 | player2.win(); 184 | } else { 185 | player1.even(); 186 | player2.even(); 187 | } 188 | } 189 | 190 | println!("Total result:"); 191 | println!("{}", player1); 192 | println!("{}", player2); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/template_method_new.rs: -------------------------------------------------------------------------------- 1 | pub enum DisplayType { 2 | Char(char), 3 | String(String), 4 | } 5 | 6 | impl DisplayType { 7 | pub fn display(&self) { 8 | self.open(); 9 | for _ in 0..5 { 10 | self.print(); 11 | } 12 | self.close(); 13 | } 14 | 15 | fn print_line(&self) { 16 | match self { 17 | DisplayType::Char(..) => {} 18 | DisplayType::String(s) => { 19 | print!("+"); 20 | for _ in 0..s.len() { 21 | print!("-"); 22 | } 23 | println!("+"); 24 | } 25 | } 26 | } 27 | 28 | fn open(&self) { 29 | match self { 30 | DisplayType::Char(..) => print!("<<"), 31 | DisplayType::String(..) => self.print_line(), 32 | } 33 | } 34 | 35 | fn print(&self) { 36 | match self { 37 | DisplayType::Char(c) => print!("{}", c), 38 | DisplayType::String(s) => println!("|{}|", s), 39 | } 40 | } 41 | 42 | fn close(&self) { 43 | match self { 44 | DisplayType::Char(..) => println!(">>"), 45 | DisplayType::String(..) => self.print_line(), 46 | } 47 | } 48 | } 49 | 50 | #[cfg(test)] 51 | mod test { 52 | use super::*; 53 | 54 | #[test] 55 | fn test() { 56 | let d1 = DisplayType::Char('H'); 57 | let d2 = DisplayType::String("Hello,world.".to_owned()); 58 | 59 | d1.display(); 60 | d2.display(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/template_method_old.rs: -------------------------------------------------------------------------------- 1 | trait Operation { 2 | fn open(&self); 3 | fn print(&self); 4 | fn close(&self); 5 | } 6 | 7 | pub trait AbstractDisplay: Operation { 8 | fn display(&self) { 9 | self.open(); 10 | for _ in 0..5 { 11 | self.print(); 12 | } 13 | self.close(); 14 | } 15 | } 16 | 17 | #[derive(Debug)] 18 | pub struct CharDisplay(char); 19 | 20 | impl CharDisplay { 21 | pub fn new(c: char) -> Self { 22 | Self(c) 23 | } 24 | } 25 | 26 | impl Operation for CharDisplay { 27 | fn open(&self) { 28 | print!("<<"); 29 | } 30 | 31 | fn print(&self) { 32 | print!("{}", self.0); 33 | } 34 | 35 | fn close(&self) { 36 | println!(">>"); 37 | } 38 | } 39 | 40 | impl AbstractDisplay for CharDisplay {} 41 | 42 | #[derive(Debug)] 43 | pub struct StringDisplay(String, usize); 44 | 45 | impl StringDisplay { 46 | pub fn new(s: String) -> Self { 47 | let w = s.len(); 48 | Self(s, w) 49 | } 50 | 51 | fn print_line(&self) { 52 | print!("+"); 53 | for _ in 0..self.1 { 54 | print!("-"); 55 | } 56 | println!("+"); 57 | } 58 | } 59 | 60 | impl Operation for StringDisplay { 61 | fn open(&self) { 62 | self.print_line(); 63 | } 64 | 65 | fn print(&self) { 66 | println!("|{}|", self.0); 67 | } 68 | 69 | fn close(&self) { 70 | self.print_line(); 71 | } 72 | } 73 | 74 | impl AbstractDisplay for StringDisplay {} 75 | 76 | #[cfg(test)] 77 | mod test { 78 | use super::*; 79 | 80 | #[test] 81 | fn _1_usage_static_dispatch_generic() { 82 | let d1: CharDisplay = CharDisplay::new('H'); 83 | let d2: StringDisplay = StringDisplay::new("Hello,world.".to_owned()); 84 | 85 | fn display(ad: T) { 86 | ad.display(); 87 | } 88 | 89 | display(d1); 90 | display(d2); 91 | } 92 | 93 | #[test] 94 | fn _2_usage_static_dispatch_impl_trait() { 95 | let d1: CharDisplay = CharDisplay::new('H'); 96 | let d2: StringDisplay = StringDisplay::new("Hello,world.".to_owned()); 97 | 98 | // impl traitはgenericのシンタックスシュガー 99 | fn display(ad: impl AbstractDisplay) { 100 | ad.display(); 101 | } 102 | 103 | display(d1); 104 | display(d2); 105 | } 106 | 107 | #[test] 108 | fn _3_usage_dynamic_dispatch() { 109 | let d1: Box = Box::new(CharDisplay::new('H')); 110 | let d2: Box = Box::new(StringDisplay::new("Hello,world.".to_owned())); 111 | 112 | fn display(ad: Box) { 113 | ad.display(); 114 | } 115 | 116 | display(d1); 117 | display(d2); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/visitor.rs: -------------------------------------------------------------------------------- 1 | mod enum_base; 2 | mod trait_base; 3 | -------------------------------------------------------------------------------- /src/visitor/enum_base.rs: -------------------------------------------------------------------------------- 1 | pub enum Visitor { 2 | HtmlExporterVisitor { builder: String }, 3 | PlainTextExporterVisitor { builder: String }, 4 | } 5 | 6 | impl Visitor { 7 | pub fn get_result(&self) -> &str { 8 | match self { 9 | Visitor::HtmlExporterVisitor { builder } => builder, 10 | Visitor::PlainTextExporterVisitor { builder } => builder, 11 | } 12 | } 13 | 14 | pub fn of_html_exporter() -> Self { 15 | Visitor::HtmlExporterVisitor { builder: "".to_owned() } 16 | } 17 | 18 | pub fn of_plain_text_exporter() -> Self { 19 | Visitor::PlainTextExporterVisitor { builder: "".to_owned() } 20 | } 21 | 22 | pub fn visit_title(&mut self, title: &Title) { 23 | match self { 24 | Visitor::HtmlExporterVisitor { builder } => builder.push_str(&format!("

{}

\n", title.text)), 25 | Visitor::PlainTextExporterVisitor { builder } => builder.push_str(&format!("{}\n", title.text)), 26 | } 27 | } 28 | 29 | pub fn visit_text(&mut self, text: &Text) { 30 | match self { 31 | Visitor::HtmlExporterVisitor { builder } => builder.push_str(&format!("

{}

\n", text.text)), 32 | Visitor::PlainTextExporterVisitor { builder } => builder.push_str(&format!("{}\n", text.text)), 33 | } 34 | } 35 | 36 | pub fn visit_hyperlink(&mut self, hyperlink: &HyperLink) { 37 | match self { 38 | Visitor::HtmlExporterVisitor { builder } => { 39 | builder.push_str(&format!("{}\n", hyperlink.url, hyperlink.text)) 40 | } 41 | Visitor::PlainTextExporterVisitor { builder } => { 42 | builder.push_str(&format!("{} {}\n", hyperlink.text, hyperlink.url)) 43 | } 44 | } 45 | } 46 | } 47 | 48 | #[derive(Debug)] 49 | pub enum Element { 50 | Title(Title), 51 | Text(Text), 52 | HyperLink(HyperLink), 53 | } 54 | 55 | impl Element { 56 | pub fn of_title(s: &str) -> Self { 57 | Element::Title(Title::new(s)) 58 | } 59 | 60 | pub fn of_text(s: &str) -> Self { 61 | Element::Text(Text::new(s)) 62 | } 63 | 64 | pub fn of_hyper_link(text: &str, url: &str) -> Self { 65 | Element::HyperLink(HyperLink::new(text, url)) 66 | } 67 | 68 | pub fn accept(&self, visitor: &mut Visitor) { 69 | match self { 70 | Element::Title(inner) => inner.accept(visitor), 71 | Element::Text(inner) => inner.accept(visitor), 72 | Element::HyperLink(inner) => inner.accept(visitor), 73 | } 74 | } 75 | } 76 | 77 | #[derive(Debug)] 78 | pub struct Title { 79 | text: String, 80 | } 81 | 82 | impl Title { 83 | pub fn new(text: &str) -> Self { 84 | Self { text: text.to_owned() } 85 | } 86 | 87 | pub fn accept(&self, visitor: &mut Visitor) { 88 | visitor.visit_title(self) 89 | } 90 | } 91 | 92 | #[derive(Debug)] 93 | pub struct Text { 94 | text: String, 95 | } 96 | 97 | impl Text { 98 | pub fn new(text: &str) -> Self { 99 | Self { text: text.to_owned() } 100 | } 101 | 102 | pub fn accept(&self, visitor: &mut Visitor) { 103 | visitor.visit_text(self) 104 | } 105 | } 106 | 107 | #[derive(Debug)] 108 | pub struct HyperLink { 109 | text: String, 110 | url: String, 111 | } 112 | 113 | impl HyperLink { 114 | pub fn new(text: &str, url: &str) -> Self { 115 | Self { 116 | text: text.to_owned(), 117 | url: url.to_owned(), 118 | } 119 | } 120 | 121 | pub fn accept(&self, visitor: &mut Visitor) { 122 | visitor.visit_hyperlink(self) 123 | } 124 | } 125 | 126 | #[derive(Debug)] 127 | pub struct Document { 128 | parts: Vec, 129 | } 130 | 131 | impl Document { 132 | pub fn new(parts: impl IntoIterator) -> Self { 133 | Self { 134 | parts: parts.into_iter().collect(), 135 | } 136 | } 137 | 138 | pub fn accept(&self, visitor: &mut Visitor) { 139 | for e in &self.parts { 140 | e.accept(visitor) 141 | } 142 | } 143 | } 144 | 145 | #[cfg(test)] 146 | mod test { 147 | use super::*; 148 | 149 | #[test] 150 | fn test() { 151 | let values: Vec = vec![ 152 | Element::of_title("The Visitor Pattern Example"), 153 | Element::of_text("The visitor pattern helps us add extra functionality without changing the classes."), 154 | Element::of_hyper_link("Go check it online!", "https://www.google.com/"), 155 | Element::of_text("Thanks!"), 156 | ]; 157 | 158 | let document = Document::new(values); 159 | let mut html_exporter = Visitor::of_html_exporter(); 160 | let mut plain_text_exporter = Visitor::of_plain_text_exporter(); 161 | 162 | println!("Export to html:"); 163 | document.accept(&mut html_exporter); 164 | println!("{}", html_exporter.get_result()); 165 | 166 | println!("Export to plain:"); 167 | document.accept(&mut plain_text_exporter); 168 | println!("{}", plain_text_exporter.get_result()); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /src/visitor/trait_base.rs: -------------------------------------------------------------------------------- 1 | use std::fmt::Debug; 2 | 3 | pub trait Visitor { 4 | fn visit_title(&mut self, title: &Title); 5 | fn visit_text(&mut self, text: &Text); 6 | fn visit_hyperlink(&mut self, hyperlink: &HyperLink); 7 | } 8 | 9 | pub trait Element: Debug { 10 | fn accept(&self, visitor: &mut dyn Visitor); 11 | } 12 | 13 | #[derive(Debug)] 14 | pub struct Title<'a> { 15 | text: &'a str, 16 | } 17 | 18 | impl<'a> Title<'a> { 19 | pub fn new(text: &'a str) -> Self { 20 | Self { text } 21 | } 22 | } 23 | 24 | impl<'a> Element for Title<'a> { 25 | fn accept(&self, visitor: &mut dyn Visitor) { 26 | visitor.visit_title(self) 27 | } 28 | } 29 | 30 | #[derive(Debug)] 31 | pub struct Text<'a> { 32 | text: &'a str, 33 | } 34 | 35 | impl<'a> Text<'a> { 36 | pub fn new(text: &'a str) -> Self { 37 | Self { text } 38 | } 39 | } 40 | 41 | impl<'a> Element for Text<'a> { 42 | fn accept(&self, visitor: &mut dyn Visitor) { 43 | visitor.visit_text(self) 44 | } 45 | } 46 | 47 | #[derive(Debug)] 48 | pub struct HyperLink<'a> { 49 | text: &'a str, 50 | url: &'a str, 51 | } 52 | 53 | impl<'a> HyperLink<'a> { 54 | pub fn new(text: &'a str, url: &'a str) -> Self { 55 | Self { text, url } 56 | } 57 | } 58 | 59 | impl<'a> Element for HyperLink<'a> { 60 | fn accept(&self, visitor: &mut dyn Visitor) { 61 | visitor.visit_hyperlink(self) 62 | } 63 | } 64 | 65 | #[derive(Debug)] 66 | pub struct Document<'a> { 67 | parts: Vec>, 68 | } 69 | 70 | impl<'a> Document<'a> { 71 | pub fn new(parts: impl IntoIterator>) -> Self { 72 | Self { 73 | parts: parts.into_iter().collect(), 74 | } 75 | } 76 | 77 | pub fn accept(&self, visitor: &mut dyn Visitor) { 78 | for e in &self.parts { 79 | e.accept(visitor) 80 | } 81 | } 82 | } 83 | 84 | #[derive(Debug, Default)] 85 | pub struct HtmlExporterVisitor { 86 | builder: String, 87 | } 88 | 89 | impl HtmlExporterVisitor { 90 | pub fn new() -> Self { 91 | Self::default() 92 | } 93 | 94 | pub fn get_html(&self) -> &str { 95 | &self.builder 96 | } 97 | } 98 | 99 | impl Visitor for HtmlExporterVisitor { 100 | fn visit_title(&mut self, title: &Title) { 101 | self.builder.push_str(&format!("

{}

\n", title.text)); 102 | } 103 | 104 | fn visit_text(&mut self, text: &Text) { 105 | self.builder.push_str(&format!("

{}

\n", text.text)); 106 | } 107 | 108 | fn visit_hyperlink(&mut self, hyperlink: &HyperLink) { 109 | self 110 | .builder 111 | .push_str(&format!("{}\n", hyperlink.url, hyperlink.text)); 112 | } 113 | } 114 | 115 | #[derive(Debug, Default)] 116 | pub struct PlainTextExporterVisitor { 117 | builder: String, 118 | } 119 | 120 | impl PlainTextExporterVisitor { 121 | pub fn new() -> Self { 122 | Self::default() 123 | } 124 | 125 | pub fn get_text(&self) -> &str { 126 | &self.builder 127 | } 128 | } 129 | 130 | impl Visitor for PlainTextExporterVisitor { 131 | fn visit_title(&mut self, title: &Title) { 132 | self.builder.push_str(&format!("{}\n", title.text)); 133 | } 134 | 135 | fn visit_text(&mut self, text: &Text) { 136 | self.builder.push_str(&format!("{}\n", text.text)); 137 | } 138 | 139 | fn visit_hyperlink(&mut self, hyperlink: &HyperLink) { 140 | self 141 | .builder 142 | .push_str(&format!("{} {}\n", hyperlink.text, hyperlink.url)); 143 | } 144 | } 145 | 146 | #[cfg(test)] 147 | mod test { 148 | use super::*; 149 | 150 | #[test] 151 | fn test() { 152 | let values: Vec> = vec![ 153 | Box::new(Title::new("The Visitor Pattern Example")), 154 | Box::new(Text::new( 155 | "The visitor pattern helps us add extra functionality without changing the classes.", 156 | )), 157 | Box::new(HyperLink::new("Go check it online!", "https://www.google.com/")), 158 | Box::new(Text::new("Thanks!")), 159 | ]; 160 | let document = Document::new(values); 161 | 162 | let mut html_exporter = HtmlExporterVisitor::new(); 163 | let mut plain_text_exporter = PlainTextExporterVisitor::new(); 164 | 165 | println!("Export to html:"); 166 | document.accept(&mut html_exporter); 167 | println!("{}", html_exporter.get_html()); 168 | 169 | println!("Export to plain:"); 170 | document.accept(&mut plain_text_exporter); 171 | println!("{}", plain_text_exporter.get_text()); 172 | } 173 | } 174 | --------------------------------------------------------------------------------