{"id":445438,"date":"2025-01-19T15:01:16","date_gmt":"2025-01-19T15:01:16","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=445438"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2025-01-19T15:01:16","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=445438","title":{"rendered":"<span>\u041d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0435 \u043f\u043b\u044e\u0441\u044b \u044f\u0437\u044b\u043a\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0420\u0430\u0441\u0442 \u0445\u043e\u0440\u043e\u0448, \u0432\u0441\u0435 \u044d\u0442\u043e \u0437\u043d\u0430\u044e\u0442. \u0418\u043d\u0432\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0448\u044c \u0432\u0440\u0435\u043c\u044f \u0432 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u0430\u0439\u0444\u0443\u0435\u0448\u044c, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0448\u044c c \u0440\u0438\u0441\u043a\u0430\u043c\u0438, \u0437\u0430\u0434\u0430\u0435\u0448\u044c\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u043c &#8212; \u0430 \u043c\u043e\u0436\u0435\u0442, \u0440\u0430\u0441\u0442 \u0435\u0449\u0435 \u043a\u0440\u0443\u0447\u0435? \u041f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0435 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u043b\u0438\u0434\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043f\u043b\u044e\u0441\u0430\u0445 (5k \u0437\u0432\u0435\u0437\u0434 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431\u0435) &#8212; \u0438 \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e. \u0412\u0440\u043e\u0434\u0435, \u0432\u0441\u0435 \u0442\u0430\u043a \u0434\u0435\u043b\u0430\u044e\u0442, \u043d\u043e \u043c\u043e\u0436\u0435\u0442, \u0441\u0443\u0442\u044c \u0432 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0438\u0434\u0435\u0439, \u0430 \u043d\u0435 \u043a\u043e\u0434\u0430. \u0411\u044b\u0442\u044c \u043c\u043e\u0436\u0435\u0442, \u043c\u044b \u043d\u0430\u0439\u0434\u0435\u043c \u043e\u0442\u0432\u0435\u0442\u044b \u043e \u0432\u044b\u0440\u0430\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u044f\u0437\u044b\u043a\u0430, \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u0438 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0430\u043c \u0441\u0442\u0430\u043d\u0435\u0442 \u044f\u0441\u043d\u043e &#8212; \u0430 \u0434\u0440\u0443\u0433 \u043b\u0438 \u043d\u0430\u0448 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440, \u043d\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043c\u044b \u043d\u0430\u0441\u043b\u0430\u0434\u0438\u043c\u0441\u044f \u044d\u0441\u0442\u0435\u0442\u0438\u043a\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0440\u0430\u0441\u0442e.<\/p>\n<p>\u0421\u0442\u0440\u0430\u043d\u0430 \u0431\u043e\u0433\u0430\u0442\u0430 \u0438\u0434\u0435\u044f\u043c\u0438, \u043a\u0430\u043a \u0447\u0438\u0442\u0430\u0442\u044c \u043a\u043e\u0434: \u0431\u043b\u043e\u043a-\u0441\u0445\u0435\u043c\u044b, \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438, \u0444\u0430\u0439\u043b \u0447\u0435\u0440\u0435\u0437 \u0444\u0430\u0439\u043b \u0438 \u0442.\u0434. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043c\u0435\u0442\u043e\u0434 &#8212; \u044d\u0442\u043e \u0447\u0442\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u0440\u044f\u0434. \u042f \u0432\u044b\u0431\u0440\u0430\u043b \u0442\u0435\u043c\u0443, \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u0442\u043e\u0447\u043d\u043e (\u0445\u043e\u0442\u044f \u0431\u044b \u043a\u0440\u0430\u0435\u043c \u0443\u0445\u0430): \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0414\u0430\u043b\u0435\u0435 \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 \u0431\u0443\u0434\u0435\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u0432\u0435\u0431 \u0441\u0435\u0440\u0432\u0435\u0440 crowCpp (\u0441\u0441\u044b\u043b\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0438\u0436\u0435) \u0438 \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c (\u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u043e\u043f\u043b\u043e\u0449\u0430\u0442\u044c \u0435\u0433\u043e \u0438\u0434\u0435\u0438) \u043d\u0430 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0441\u0442.<\/p>\n<p>\u041e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0442\u043a\u043e \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u043d\u0430 \u043f\u043e\u043b\u044f\u0445 \u043f\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044e (<a href=\"https:\/\/github.com\/CrowCpp\/Crow\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/CrowCpp\/Crow<\/a>):<\/p>\n<p>http_request.h &#8212; \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u043a\u043e\u0434, \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438\/\u043c\u0435\u0442\u043e\u0434\u044b, \u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0431\u0435\u0437 \u0434\u043e\u043a\u043e\u0432 \u0444\u0438\u0433 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u0448\u044c, \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0438\u043b\u0438 \u043d\u0435\u0442).<\/p>\n<p>http_response.h &#8212; \u043c\u043d\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u043e\u0432 std::move, \u043f\u0440\u0438 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043d\u0435 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0445 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b &#8212; \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043c\u043d\u043e\u0433\u043e \u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u0444\u043b\u0430\u0433\u043e\u0432\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0442.\u0434.<\/p>\n<p>http_connection.h &#8212; \u043f\u0440\u0438\u0432\u0435\u0442, \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u044f (\u0432 \u043f\u0440\u0438\u0440\u043e\u0434\u0435 \u043f\u043e\u043a\u0430 \u0435\u0449\u0435 \u043d\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0435\u0437 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438 \ud83d\ude42<\/p>\n<p>http_server.h &#8212; \u043f\u0435\u0440\u0435\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0435\u043d\u0438\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 (load balancing) \u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c &#171;\u0442\u0443\u0434\u0443&#187;, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0435\u0449\u0435 \u043f\u0430\u0440\u0443 \u0431\u0430\u0439\u0442.<\/p>\n<p>app.h &#8212; \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0438 \u043c\u0430\u043a\u0440\u043e\u0441\u044b.<br \/> socket_adaptors.h &#8212; \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 \u0441\u043e\u043a\u0435\u0442\u043e\u043c.<\/p>\n<p>routing.h &#8212; \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043a\u043e\u0434\u0430:<\/p>\n<pre><code class=\"cpp\">void handle_upgrade(...) override {     max_payload_ = max_payload_override_ ? max_payload_ : app_-&gt;websocket_max_payload();     new crow::websocket::Connection&lt;SocketAdaptor, App&gt;(req, std::move(adaptor), app_, max_payload_, ...); } <\/code><\/pre>\n<p>\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 \u044f\u0432\u0443, \u043d\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 websocket::Connection \u0441\u0430\u043c \u0441\u0435\u0431\u044f \u0438 \u043f\u043e\u0434\u0447\u0438\u0449\u0430\u0435\u0442<\/p>\n<pre><code class=\"cpp\">... adaptor_.close(); handler_-&gt;remove_websocket(this); delete this; <\/code><\/pre>\n<p>\u0435\u0449\u0435_\u043c\u043d\u043e\u0433\u043e_\u0444\u0430\u0439\u043b\u043e\u0432.h &#8212; \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u0438\u0447\u0435\u0439, \u043d\u043e \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435, \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 1: \u041f\u0438\u043d\u0433-\u041f\u043e\u043d\u0433<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u0438 \u0443\u043f\u043e\u0440\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u043f\u0438\u0442\u0438\u044f \u043a\u0440\u0435\u043f\u043a\u043e\u0433\u043e \u043a\u043e\u0444\u0435, \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 \u043e \u0434\u043e\u0442\u0435, \u0448\u0430\u0445\u043c\u0430\u0442\u0430\u0445 \u0438 \u0441\u043d\u0443\u043a\u0435\u0440\u0435, \u0435\u0449\u0435 \u0438 \u0442\u0435\u043b\u0435\u0433\u0438 (\u0442\u0443\u0442 \u043d\u0438\u043a\u0443\u0434\u0430) &#8212; \u0434\u0438\u0437\u0430\u0439\u043d\u0438\u043c \u043d\u0430 \u0441\u0430\u043b\u0444\u0435\u0442\u043a\u0435 \u043f\u0440\u043e\u0435\u043a\u0442: \u0441\u043e\u043a\u0435\u0442 -&gt; \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d -&gt; \u0441\u0435\u0440\u0432\u0435\u0440 -&gt; \u0430\u043f\u043f (\u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u0438 \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u0433\u0434\u0435-\u0442\u043e \u0441\u0431\u043e\u043a\u0443, \u0440\u043e\u0443\u0442\u0435\u0440 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u0430\u043f\u043f).<\/p>\n<p>\u041a\u0430\u043a-\u0442\u043e \u0442\u0430\u043a, \u0435\u0449\u0435 \u0440\u0430\u0437: \u0430\u043f\u043f\u043b\u0438\u043a\u0435\u0439\u0448\u043d -&gt; \u0441\u0435\u0440\u0432\u0435\u0440 -&gt; \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d -&gt; \u0441\u043e\u043a\u0435\u0442. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441:<\/p>\n<pre><code class=\"rust\">route![app, \"\/\", || \"Hello world\".to_owned()]; route![app, \"\/measure\/&lt;float&gt;\/and\/&lt;int&gt;\", |x,y,_req| format!(\"{:?} and {:?}\" x, y)]; <\/code><\/pre>\n<p>\u0425\u043e\u0434\u044f\u0442 \u0441\u043b\u0443\u0445\u0438, \u0447\u0442\u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u043a\u043e\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0441\u0442\u0440\u043e\u0447\u043a\u0430 \u0437\u0430 \u0441\u0442\u0440\u043e\u0447\u043a\u043e\u0439 \u0441pp -&gt; rust, \u0430 \u043c\u043e\u0436\u043d\u043e \u0438 \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043d\u0443\u043b\u044f, \u0445\u043e\u0442\u044f, \u043a\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u043b \u0431\u044b \u0414\u0436\u043e\u044d\u043b\u044c \u0421\u043f\u043e\u043b\u044c\u0441\u043a\u0438 &#8212; \u0431\u0443\u0434\u0443\u0442 \u0431\u0430\u0433\u0438, \u0434\u0430 \u0438 \u0444\u0438\u0433 \u0441 \u043d\u0438\u043c\u0438, \u043f\u0440\u043e\u0435\u043a\u0442-\u0442\u043e \u0443\u0447\u0435\u0431\u043d\u044b\u0439. \u0422\u0430\u043a\u0436\u0435 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u044b \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u043c\/\u0445\u043e\u0442\u0438\u043c, \u0438 \u0432\u0435\u0440\u0441\u0438\u044e \u0445\u0442\u0442\u043f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e 1.1. \u0412\u0441\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u0432\u0435\u043b\u0438\u043a\u043e\u043b\u0435\u043f\u043d\u044b\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0438 \u0441 \u0431\u0435\u0447\u043c\u0430\u0440\u043a\u0430\u043c\u0438, \u043d\u043e \u0445\u043e\u0442\u044c \u043a\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u043a\u0430\u0437\u0430\u043b \u0431\u044b &#8212; \u0437\u043d\u0430\u0435\u0442\u0435, \u0431\u0435\u0447\u043c\u0430\u0440\u043a\u0438 \u0443 \u043d\u0430\u0441 \u043d\u043e\u0440\u043c\u0443\u043b\u044c, \u0430 \u043a\u043e\u0434 \u0435\u0449\u0435 \u043b\u0443\u0447\u0448\u0435 &#8212; \u0442\u0443\u043f\u043e \u0447\u0438\u0442\u0430\u0435\u043c, \u0434\u0430 \u0438 \u0441 \u0444\u043b\u0430\u0433\u0430\u043c\u0438 (\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430 300) \u043c\u044b \u043d\u0435 \u0431\u0430\u043b\u0443\u0435\u043c\u0441\u044f.<\/p>\n<p>\u041a\u043e\u043d\u043d\u0435\u043a\u0448\u043d.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ connection.rs  pub struct Connection { socket: Socket, }  impl Connection { pub fn new(stream: TcpStream) -&gt; Self { Connection { socket: Socket::new(stream), } } }  impl Connection{ pub async fn start(&amp;mut self, app: &amp;App) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; { let s = self.socket.read_all().await?; if !s.is_empty() { let req = Parser::new(s).parse().ok_or(\"failed to parse\")?; let resp = app.handle(req).await;         self.socket.write_all(resp).await?;     }     Ok(()) } } <\/code><\/pre>\n<p>\u0414\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c \u0441 \u0440\u0430\u0441\u0442\u043e\u043c: 1) \u0444\u044c\u044e\u0447\u0435\u0440\u0441\u044b \u0431\u0435\u0437 await \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u044e\u0442, 2) \u0437\u043d\u0430\u043a\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 &#8212; \u0435\u0441\u0442\u044c \u043d\u0435\u044f\u0432\u043d\u0430\u044f \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u043a\u0430 Result \u0438\u043b\u0438 Option.<\/p>\n<p>\u041f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0439 \u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 \u0445\u0442\u0442\u043f \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/p>\n<pre><code class=\"rust\">\/\/\/ parser.rs  pub struct Parser&lt;'a&gt; { s: &amp;'a str, }  impl &lt;'a&gt; Parser&lt;'a&gt; { pub fn new(s: &amp;'a str) -&gt; Self { Parser { s } } }  impl Parser&lt;'_&gt; { pub fn parse(self) -&gt; Option&lt;Request&gt; { let (mut info, mut headers) = (vec![], vec![]);  let mut iter = self.s.split(\"\\r\\n\"); for x in iter.next()?.split(' ') {  info.push(x);  } for x in iter.by_ref() { if x.is_empty() { break; } let mut b = x.split(\": \"); headers.push(( b.next()?.to_owned(),  b.next()?.to_owned() )); } let body = iter.next()?.to_owned();  Request::build(info, headers, body) } }  <\/code><\/pre>\n<p>\u0414\u0432\u0430 \u043c\u043e\u043c\u0435\u043d\u0442\u0430: 1) \u043c\u0435\u0442\u043e\u0434 parse \u043f\u043e\u0433\u043b\u043e\u0442\u0438\u0442 \u043e\u0431\u044c\u0435\u043a\u0442 (self \u0431\u0435\u0437 \u0430\u043c\u043f\u0435\u0440\u0441\u0430\u043d\u0434\u0430) &#8212; \u0433\u0443\u0434 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438; 2) lifetime (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u043f\u043e\u0441\u0442\u0440\u043e\u0444) \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u044e\u0437\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0431\u0443\u0444\u0435\u0440 \u0441\u043e\u043a\u0435\u0442\u0430 (\u0447\u0435\u0440\u0435\u0437 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443) \u043f\u043e\u0441\u043b\u0435 \u0435\u0433\u043e (\u0431\u0443\u0444\u0435\u0440\u0430) \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0420\u0435\u043a\u0432\u0435\u0441\u0442.pc &#8212; \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u043c\u0443 \u043a\u043e\u0434\u0443.<\/p>\n<pre><code class=\"rust\">\/\/\/ request.rs  #[derive(Default, Debug, Clone)] pub struct Request { pub method: String, pub url: String, pub version: String, pub query: String, pub headers: Vec&lt;(String, String)&gt;, pub body: String,   }  fn parse_url(s: &amp;str) -&gt; (String, String) { if let Some(i) = s.find('?') { (s[..i].to_owned(), s[i+1..].to_owned()) } else { (s.to_owned(), \"\".to_owned()) } }  impl Request { pub fn build(mut info: Vec&lt;&amp;str&gt;, headers: Vec&lt;(String, String)&gt;, body: String) -&gt; Option&lt;Self&gt; { let version = info.pop()?.to_owned(); let (url, query) = parse_url(info.pop()?); let method = info.pop()?.to_owned(); Some(Request {method, url, query, version, headers, body}) } } <\/code><\/pre>\n<p>\u0420\u0435\u0441\u043f\u043e\u043d\u0441 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0442\u0440\u0438\u043d\u0433\u043e\u043c (String).<\/p>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0441\u043e\u043a\u0435\u0442\u0430\u043c &#8212; \u0421\u043e\u043a\u0435\u0442.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ socket.rs  pub struct Socket { stream: TcpStream, buf: [u8; 1024], }  impl Socket { pub fn new(stream: TcpStream) -&gt; Self {     Socket { stream, buf: [0; 1024] } } }  impl Socket {  pub async fn read_all(&amp;mut self) -&gt; Result&lt;&amp;str, Box&lt;dyn Error&gt;&gt; { let n = self.stream.read(&amp;mut self.buf).await?; Ok(std::str::from_utf8(&amp;self.buf[..n])?) }  pub async fn write_all(&amp;mut self, s: String) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; { let x = format!(\"HTTP\/1.1 200 OK\\r\\nContent-Length: {}\\r\\n\\n\", s.len()); self.stream.write_all(&amp;x.into_bytes()).await?; self.stream.write_all(&amp;s.into_bytes()).await?; Ok(()) } } <\/code><\/pre>\n<p>\u041f\u0430\u0440\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432: 1) \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c, \u0447\u0442\u043e \u0431\u0443\u0444\u0435\u0440 \u0432\u043c\u0435\u0441\u0442\u0438\u0442 \u0432\u0435\u0441\u044c \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445, 2) \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u043c \u0431\u0443\u0444\u0435\u0440 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0441\u043e\u043a\u0435\u0442\u043e\u043c \u0438\u0437-\u0437\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, 3) \u0440\u0430\u0437\u043c\u0435\u0440 \u0431\u0443\u0444\u0435\u0440\u0430 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b, 4) \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0445\u0435\u0434\u0435\u0440\u0430.<\/p>\n<p>\u0421\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 &#8212; \u0421\u0435\u0440\u0432\u0435\u0440.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ server.rs  pub struct Server { listener: TcpListener, }  impl Server { pub async fn bind(addr: &amp;str) -&gt; Result&lt;Server, Box&lt;dyn Error&gt;&gt; { let listener = TcpListener::bind(&amp;addr).await?;     println!(\"Listening on: {addr}\");     Ok(Server{listener}) }  pub async fn accept(&amp;mut self, app: &amp;'static App) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; { loop { let (stream, _) = self.listener.accept().await?; tokio::spawn(async move { let mut p = Connection::new(stream); p.start(app).await.unwrap(); }); } } } <\/code><\/pre>\n<p>\u0420\u0435\u0431\u044f\u0442\u0430 \u0438\u0437 CrowCpp \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 (\u043d\u0430 \u0431\u0430\u0437\u0435 boost::asio) \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0449\u0438\u043a \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0443 \u0440\u0430\u0441\u0442\u0430 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u0435\u0441\u0435\u043b\u0435\u0435 &#8212; \u0435\u0441\u0442\u044c tokio \u0440\u0430\u043d\u0442\u0430\u0439\u043c. \u042d\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u0440\u0430\u043d\u0442\u0430\u0439\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0435\u0440\u0435\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u044e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0430\u0441\u043a\u043e\u0432, \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0443 (\u0441\u0430\u043c\u0443\u044e \u0431\u0430\u0437\u043e\u0432\u0443\u044e) \u0438 \u0442.\u0434.<\/p>\n<p>\u0418\u0437 \u0434\u043e\u043a\u043e\u0432 tokio::spawn<br \/> <code>Spawning a task enables the task to execute concurrently to other tasks. The spawned task may execute on the current thread, or it may be sent to a different thread to be executed.<\/code><\/p>\n<p>\u0415\u0449\u0435 \u0434\u043e\u043a\u0438 \u043e \u0442\u043e\u043a\u0438\u0439\u0441\u043a\u043e\u043c \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435:<br \/> <code>The multi-thread scheduler executes futures on a\u00a0thread pool, using a work-stealing strategy. By default, it will start a worker thread for each CPU core available on the system. This tends to be the ideal configuration for most applications.<\/code><\/p>\n<p>\u0422\u0430\u0441\u043a\u0438 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0430 \u043d\u0435 \u043b\u044e\u0431\u044f\u0442 \u0431\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437\u0432\u043d\u0435, \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0430\u043f\u043f\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0442\u0432\u043e\u0440\u0438\u0442\u044c\u0441\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c (\u0441\u043c. \u0432 \u043a\u043e\u0434\u0435 &#8212; \u0441\u0442\u0430\u0442\u0438\u043a \u0441\u0441\u044b\u043b\u043a\u0430 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0432\u043d\u0430 \u0432\u044d\u043b\u044c\u044e \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432) \u0438 \u043f\u0435\u0440\u0435\u043f\u0440\u044b\u0433\u043d\u0443\u0442\u044c \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u0442\u0430\u0441\u043a\u0443. \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d\u0430 \u0432\u0437\u044f\u043b \u0443 \u0440\u0435\u0431\u044f\u0442 \u0438\u0437 CrowCpp, \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u0442\u0430\u043a \u0438 \u043d\u0435 \u0441\u043c\u043e\u0433 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u043b\u0443\u0447\u0448\u0435 \ud83d\ude42<\/p>\n<p>\u0426\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043a\u0430 &#8212; a\u043f\u043f.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ app.rs  #[derive(Default)] pub struct App { map: Trie&lt;fn(Request, Vec&lt;RouteTokens&gt;) -&gt; String&gt;, }  unsafe fn make_static&lt;T&gt;(t: &amp;T) -&gt; &amp;'static T {     std::mem::transmute(t) }  impl App { pub async fn start(&amp;self, addr: &amp;str) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; {     let mut server = Server::bind(addr).await?;     \/\/ safe: app should be alive before termination     server.accept(unsafe { make_static(self) }).await?;     Ok(()) }  pub async fn handle(&amp;self, req: Request) -&gt; String { let b = req.url.split('\/').filter(|s| !s.is_empty()); self.map.get(b) .map(|(fun, args)| fun(req, args)) .unwrap_or(\"Not found\".to_owned()) }  pub fn service(&amp;mut self, key: &amp;'static str, fun: fn(Request, Vec&lt;RouteTokens&gt;) -&gt; String) { let b = key.split('\/').filter(|s| !s.is_empty()); self.map.insert(b, fun); } } <\/code><\/pre>\n<p>\u0422\u0443\u0442 \u044e\u0437\u0430\u0435\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043d\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e (Trie, \u043d\u0443\u0436\u043d\u043e\u0435 \u0434\u043b\u044f \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u0432), \u0447\u0443\u0442\u044c-\u0447\u0443\u0442\u044c unsafe \u043a\u043e\u0434\u0430 (\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442, \u043f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e OK) \u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u0442\u0438\u043f\u043e\u0432: 1) fn(&#8230;) &#8212; \u0435\u0441\u0442\u044c non-capturing\u00a0closures, \u0442\u043e \u0435\u0441\u0442\u044c \u043b\u0430\u043c\u0431\u0434\u0435 \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0442 \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0438\u0437\u0432\u043d\u0435, 2) key &amp;&#8217;static str &#8212; \u043f\u0443\u0442\u044c \u0432 \u0440\u043e\u0443\u0442\u0435\u0440\u0435 \u043f\u0438\u0448\u0435\u043c (\u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432) \u0440\u0443\u0447\u043a\u0430\u043c\u0438 (\u0445\u0437, \u0445\u043e\u0440\u043e\u0448\u043e \u044d\u0442\u043e \u0438\u043b\u0438 \u043f\u043b\u043e\u0445\u043e, \u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430).<\/p>\n<p>\u041f\u0440\u0435\u0444\u0438\u043a\u0441\u043d\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e (\u043e\u043f\u044f\u0442\u044c \u0436\u0435, \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f)<\/p>\n<pre><code class=\"rust\">\/\/\/ trie.rs  pub struct Trie&lt;T&gt; { head: Node&lt;T&gt;,  }  struct Node&lt;T&gt; { value: Option&lt;T&gt;, map: HashMap&lt;&amp;'static str, Node&lt;T&gt;&gt;  }  impl&lt;T&gt; Default for Trie&lt;T&gt; { fn default() -&gt; Self { let head = Node { value: None, map: HashMap::new() }; Trie { head } } }  impl&lt;T&gt; Trie&lt;T&gt; { pub fn insert(&amp;mut self, v: impl IntoIterator&lt;Item = &amp;'static str&gt;, elem: T) { let mut node = &amp;mut self.head; for s in v { if node.map.contains_key(s) {  node = node.map.get_mut(s).unwrap(); } else { let next = Node { value: None, map: HashMap::new() }; node.map.insert(s, next); node = node.map.get_mut(s).unwrap();  } } node.value = Some(elem); }  pub fn get&lt;'a&gt;(&amp;self, v: impl IntoIterator&lt;Item = &amp;'a str&gt;) -&gt; Option&lt;(&amp;T, Vec&lt;RouteTokens&gt;)&gt; { let mut node = &amp;self.head; let mut args = vec![]; for s in v { let (s, token) = mapping(s); if node.map.contains_key(s) {  node = node.map.get(s).unwrap(); } else { return None; } if token != RouteTokens::NaN { args.push(token); } } node.value.as_ref().map(|elem| (elem, args)) } }  #[derive(Debug, PartialEq, Copy, Clone)] pub enum RouteTokens { Int(i32), Usize(usize), Float(f32), NaN }  fn mapping(s: &amp;str) -&gt; (&amp;str, RouteTokens) { use RouteTokens::{ Int, Usize, Float, NaN }; let is_usize = s.starts_with(|c: char| c.is_ascii_digit()); \/\/ bug: fix me -&gt; is_int let is_int = s.starts_with('-') &amp;&amp; s[1..].starts_with(|c: char| c.is_ascii_digit()); let is_float = (is_usize || is_int) &amp;&amp; s.contains('.'); match [is_float, is_usize, is_int] { [true, _, _] =&gt; (\"&lt;float&gt;\", Float(s.parse::&lt;f32&gt;().unwrap())), [_, true, _] =&gt; (\"&lt;usize&gt;\", Usize(s.parse::&lt;usize&gt;().unwrap())), [_, _, true] =&gt; (\"&lt;int&gt;\", Int(s.parse::&lt;i32&gt;().ok().unwrap())), _ =&gt; (s, NaN), } } <\/code><\/pre>\n<p>\u041f\u0440\u043e RouteTokens \u0431\u0443\u0434\u0435\u0442 \u0447\u0443\u0442\u044c \u043d\u0438\u0436\u0435. \u0421\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 (int, float \u0438 \u0442.\u0434.) \u0438\u0437 \u0443\u0440\u043b\u0430 \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0432 \u0440\u0443\u0447\u043a\u0443. \u0420\u0435\u0431\u044f\u0442\u0430 \u0438\u0437 CrowCpp \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u0443\u044e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e: \u0441\u0436\u0438\u043c\u0430\u044e\u0442 \u043f\u0443\u0442\u044c \u0432 \u0434\u0435\u0440\u0435\u0432\u0435, \u0435\u0441\u043b\u0438 \u043d\u0430 \u043f\u0443\u0442\u0438 \u0443 \u043a\u0430\u0436\u0434\u043e\u0439 \u043d\u043e\u0434\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u0438\u043d \u0447\u0430\u0439\u043b\u0434. \u0422\u043e \u0435\u0441\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u0438\u043d \u0437\u0430\u043f\u0440\u043e\u0441 \u0432 \u0445\u0435\u0448\u0442\u0430\u0439\u0431\u043b \u043f\u043e \u043f\u043e\u043b\u043d\u043e\u043c\u0443 \u043f\u0443\u0442\u0438. (\u0412 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0421rowCpp \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u0435\u043a\u0442\u043e\u0440 \u0432\u043c\u0435\u0441\u0442\u043e \u0445\u0435\u0448-\u0442\u0430\u0431\u043b\u0438\u0446\u044b &#8212; \u0442\u0430\u043c \u0431\u043e\u043b\u0435\u0435 \u0447\u0435\u0441\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f Trie \ud83d\ude42 \u0415\u0449\u0435 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u0440\u043e \u0430\u043b\u043b\u043e\u043a\u0430\u0446\u0438\u0438 &#8212; \u0432\u0441\u0435 \u0433\u043e\u0432\u043e\u0440\u044f\u0442, \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u044d\u0442\u043e \u043f\u043b\u043e\u0445\u043e (\u0440\u0435\u0434\u043a\u043e, \u043f\u0440\u0430\u0432\u0434\u0430, \u0433\u043e\u0432\u043e\u0440\u044f\u0442, \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043b\u043e\u0445\u043e), \u043d\u043e \u0447\u0438\u0441\u0442\u043e \u043f\u043e-\u0447\u0435\u043b\u043e\u0432\u0435\u0447\u0435\u0441\u043a\u0438 &#8212; \u0435\u0441\u043b\u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u0442\u0440\u0430\u0442\u0438\u0442\u044c \u0440\u0435\u0441\u0443\u0440\u0441\u044b, \u043b\u0443\u0447\u0448\u0435 \u0438\u0445 \u043d\u0435 \u0442\u0440\u0430\u0442\u0438\u0442\u044c (\u0441\u043c. \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 IntoIterator).<\/p>\n<p>\u041c\u0430\u043a\u0440\u043e\u0441\u044b &#8212; \u0440\u043e\u0443\u0442\u0438\u043d\u0433.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ routing.rs  #[macro_export] macro_rules! route {     ( $app:ident, $path:expr, || $handler:expr) =&gt; { $app.service( $path,  |_req, _args| $handler )      };     ( $app:ident, $path:literal, |$( $x:ident $(:$t:ty)? ),+| $handler:expr ) =&gt; {         {         $app.service(         $path,          |req, args| $crate::make_call![|$($x,)+| $handler, args, req]         )         }     }; }  #[macro_export] macro_rules! make_call {     (|$a:ident,| $handler:expr, $args:ident, $req: ident) =&gt; {{ (move |$a: Request|$handler)($req)     }};     (|$a:ident,$b:ident,| $handler:expr, $args:ident, $req:ident) =&gt; {{  (move |$a, $b: Request|$handler)($args[0], $req)     }};     (|$a:ident,$b:ident,$c:ident,| $handler:expr, $args:ident, $req:ident) =&gt; {{      (move |$a,$b,$c: Request|$handler)($args[0], $args[1], $req)     }}; } <\/code><\/pre>\n<p>\u041a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432, \u043a\u0430\u043a \u043c\u043d\u0435 \u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u043e\u0442\u043e\u043a\u043e\u043c \u0442\u043e\u043a\u0435\u043d\u043e\u0432 &#8212; \u0438 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u0440\u0430\u0441\u0442 \u0434\u0430\u0435\u0442 \u0442\u0430\u043a\u0443\u044e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u0437\u0430\u043c\u043e\u0440\u043e\u0447\u0435\u043a \u0441 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435\u043c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043b\u0438\u0431\u044b \u043f\u043e\u0434 \u043c\u0430\u043a\u0440\u043e\u0441 \u0438 \u0442.\u0434. \u041b\u043e\u0433\u0438\u043a\u0430 \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c &#8212; \u043f\u0430\u0440\u0441\u0438\u043c \u0441\u0442\u0440\u043e\u043a\u0443 \u0440\u043e\u0443\u0442\u0430, \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0442\u0438\u043f\u044b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0443\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u044e. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0443 \u0440\u0430\u0441\u0442\u0430 \u0435\u0441\u0442\u044c \u0438 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u043c\u0430\u043a\u0440\u043e\u0441\u044b (\u043a\u0430\u043a \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u0432\u044b\u0448\u0435) &#8212; \u0442\u0438\u043f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430, \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0443 \u0432\u0441\u0435\u0445 \u043a\u0440\u043e\u043c\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 RouteTokens (Int(i32), Float(f32) \u0438 \u0442.\u0434.), \u0438 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c (\u0441\u0435\u0439\u0447\u0430\u0441 \u0442\u0443\u043f\u043e \u043b\u0435\u043d\u044c) \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u043c \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u043c (\u0432 \u0440\u0430\u0441\u0442\u0435 \u043e\u043d \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f procedural macros, \u0430 \u043c\u0430\u043a\u0440\u043e\u0441\u044b \u0432\u044b\u0448\u0435 &#8212; declarative\u00a0macros).<\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0439 \u043a\u043e\u0434 &#8212; \u043c\u044d\u0439\u043d.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ main.rs  #[tokio::main] async fn main() -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; {     let addr = env::args()         .nth(1)         .unwrap_or_else(|| \"0.0.0.0:8080\".to_owned());          let mut app = App::default();      route![app, \"\/\", || \"Hello world\".to_owned()];     route![app, \"\/products\/&lt;usize&gt;\", |id,req| { format!(\"url {:?} and id {:?}\", req.url, id) }];     route![app, \"\/measure\/&lt;float&gt;\/and\/&lt;int&gt;\", |x,y,_req| format!(\"{:?} and {:?}\", x, y)];     route![app, \"\/pong\/\", |req| format!(\"XXX {:?}\", req.body) ];      app.start(&amp;addr).await?;     Ok(()) }  <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0433\u043e\u0442\u043e\u0432 \ud83d\ude42<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 2: \u041d\u0435\u0447\u0435\u0433\u043e \u0442\u0435\u0440\u044f\u0442\u044c<\/h3>\n<p>\u041c\u044b \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0442\u0435\u0440\u044f\u043b\u0438, \u0442\u043e\u0447\u043d\u0435\u0435, \u043e\u043f\u0443\u0441\u0442\u0438\u043b\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435 (\u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e) \u043f\u043e\u043b\u044f \u043e\u0431\u044c\u0435\u043a\u0442\u043e\u0432 \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u0438. \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f\u0430 \u043e\u043d\u0438 \u0431\u044b\u043b\u0438 \u043d\u0435 \u043e\u0441\u043e\u0431\u043e \u043d\u0443\u0436\u043d\u044b, \u043d\u043e \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u0430\u043c\u043e\u0435 \u0432\u0440\u0435\u043c\u044f. \u0421\u043c\u043e\u0442\u0440\u0438\u043c \u0432 \u043a\u043e\u0434.<\/p>\n<p>\u0417\u0430\u043c\u0435\u0442\u043a\u0438 \u043d\u0430 \u043f\u043e\u043b\u044f\u0445 (\u043e\u0447\u0435\u043d\u044c \u043a\u043e\u0440\u043e\u0442\u043a\u043e), \u043a\u0430\u043a\u0438\u0435 \u0435\u0449\u0435 \u0444\u0438\u0447\u0438 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438:<\/p>\n<p>http_request.h &#8212; \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043c\u0438\u0434e\u043b\u0432a\u044d\u0440<br \/> http_response.h &#8212; \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c, \u0447\u0442\u043e \u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u0443 \u043d\u0430\u0441 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a\u043e\u0439 &#8212; \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c (\u043d\u0443 \u0442\u0430\u043c \u043d\u0435 \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e, \u0435\u0441\u043b\u0438 \u0447\u0435\u0441\u0442\u043d\u043e)<\/p>\n<p>http_connection.h &#8212; 1) \u0442\u0430\u0439\u043c\u0430\u0443\u0442 \u0442\u0430\u0439\u043c\u0435\u0440 (\u0441 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c \u0442\u0443\u0434\u0443, \u043a\u0430\u043a \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c), 2) \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043c\u0438\u0434e\u043b\u0432a\u044d\u0440<\/p>\n<p>http_server.h &#8212; \u0442\u0438\u043a_\u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0438 \u043a\u043e\u043b\u043b\u0431\u0435\u043a \u0441 \u043d\u0438\u043c, \u043c\u0443\u0442\u0435\u043a\u0441\u044b, \u0442\u0430\u0441\u043a_\u0442\u0430\u0439\u043c\u0435\u0440_\u043f\u0443\u043b &#8212; \u043d\u0435 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0432 \u043d\u0430\u0448\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. \u0427\u0442\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f: \u0442\u0430\u0439\u043c-\u0430\u0443\u0442, \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0438 \u043c\u0438\u0434e\u043b\u0432a\u044d\u0440.<\/p>\n<p>app.h &#8212; \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u043d\u0430\u0434\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430\u0434 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c<\/p>\n<p>routing.h &#8212; blueprint (\u0433\u0440\u0443\u0431\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u043f\u0430\u0447\u043a\u0430 \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u0432 \u043f\u043e\u0434 \u043e\u0431\u0449\u0438\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c) &#8212; \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u043c (\u043b\u0435\u043d\u044c)<\/p>\n<p>\u041c\u0438\u0434\u0435\u043b\u0432\u0430\u044d\u0440<\/p>\n<pre><code class=\"rust\">pub trait Middleware: Default + Send + Sync + 'static {     fn run(&amp;self, req: &amp;mut Request); }  pub trait Router {     fn handle(&amp;self, req: Request) -&gt; impl Future&lt;Output = String&gt; + Send; }  \/\/\/ app.rs \/\/\/ --** some code before **--  macro_rules! routes_impls {     ( $x:ident, $( $y:ident $(,)?)* ) =&gt; {         impl&lt;$x: Middleware, $( $y: Middleware ),*&gt; Router for &amp;App&lt;($x, $( $y ),*)&gt; { fn handle(&amp;self, mut req: Request) -&gt; impl Future&lt;Output = String&gt; + Send { req.context = Some(HashMap::new()); $x::default().run(&amp;mut req); $( $y::default().run(&amp;mut req); )* App::&lt;($x, $( $y ),*)&gt;::handle(self, req) }         }         routes_impls!($( $y, )*);     };      () =&gt; { impl Router for &amp;App&lt;()&gt; { fn handle(&amp;self, req: Request) -&gt; impl Future&lt;Output = String&gt; + Send { App::&lt;()&gt;::handle(self, req) } }     }; }  routes_impls![A,B,C,D, E,F,G,H, I,J,K,L, M,N,O,P,Q];   \/\/\/ request.rs  #[derive(Default, Debug)] pub struct Request { \/\/ *( some code before )*  pub context: Option&lt;HashMap&lt;TypeId, Box&lt;dyn Any + Send&gt;&gt;&gt;, }  <\/code><\/pre>\n<p>\u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0445\u043e\u0447\u0435\u0442 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0440\u0435\u043a\u0432\u0435\u0441\u0442, \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0442 \u0442\u0440\u0430\u0439\u0442 \u041c\u0438\u0434e\u043b\u0432\u0430\u044d\u0440. \u0414\u0430\u043b\u0435\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0442\u0438\u043f \u043d\u0430\u0448\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043a\u0438 \u0432 \u0430\u043f\u043f\u0443 &#8212; \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 App&lt;(CORS, Xkey, CookieParser)&gt; &#8212; \u043f\u0440\u043e\u0444\u0438\u0442.<\/p>\n<p>\u0412 \u0440\u0430\u0441\u0442\u0435, \u043a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043d\u0435\u0442 variadic template &#8212; \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a\u043e\u0432 \u0442\u0430\u043f\u043b\u0430\u043c\u0438 (tuple) \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u043e\u0439 \u0434\u043b\u0438\u043d\u044b. \u0412 \u043a\u043e\u0434\u0435 \u0432\u044b\u0448\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u043e 17 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0442\u0430\u043f\u043b\u0435.<\/p>\n<p>\u0414\u043b\u044f \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043c\u0438\u0434\u0435\u043b\u0432\u0430\u044d\u0440\u0430\u0445 \u043d\u0443\u0436\u043d\u043e \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0432\u044b\u0440\u0435\u0437\u0430\u0442\u044c \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 &#8212; \u0442\u0430\u043a \u043a\u0430\u043a \u043a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043a\u0430 \u0437\u0430\u0445\u043e\u0447\u0435\u0442 \u0437\u0430\u044e\u0437\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u043d\u044b\u0439 \u0442\u0438\u043f. \u0412 \u0440\u0430\u0441\u0442\u0435 \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 Any, \u043f\u043b\u044e\u0441 \u043a\u0430\u0436\u0434\u044b\u0439 \u0442\u0438\u043f \u0438\u043c\u0435\u0435\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 &#8212; \u0442\u043e \u0435\u0441\u0442\u044c \u0432\u044b\u0431\u043e\u0440 \u0445\u0435\u0448 \u0442\u0430\u0431\u043b\u0438\u0446\u044b (\u043a\u0430\u043a\u043e\u0433\u043e \u043b\u0438\u0431\u043e \u043c\u0430\u043f\u043f\u0438\u043d\u0433\u0430 typeId -&gt; type) \u043d\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u0430\u043c \u0441\u043e\u0431\u043e\u0439.<\/p>\n<p>\u041d\u043e\u0432\u043e\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435<\/p>\n<pre><code class=\"rust\">\/\/\/ server.rs impl Server {  \/\/\/ --&amp;&amp;-- some code before --&amp;&amp;--   pub async fn accept(&amp;mut self, app: impl Router + Send + Copy + 'static) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; { self.listen_signals(); loop { let (stream, _) = self.listener.accept().await?; let task = tokio::spawn(timeout(self.timeout, async move { let mut p = Connection::new(stream); p.start(app).await.unwrap(); })); self.register(task); } }  pub async fn shutdown(&amp;mut self) { for t in self.tasks.drain(..) { let _ = t.await; } }  fn register(&amp;mut self, t: JoinHandle&lt;Result&lt;(), error::Elapsed&gt;&gt;) { self.tasks.push(t); let (k, next_round) = self._counter.overflowing_add(1); self._counter = k; if next_round { self.tasks.retain(|t| !t.is_finished()); } }  fn listen_signals(&amp;mut self) { \/\/ safe: `server` should be alive before termination let this = unsafe { make_mut_static(self) }; tokio::spawn(async move {     tokio::signal::ctrl_c().await.unwrap();     println!(\"\\nCTRL-C\");     println!(\"Shutdown... waiting for the tasks to complete\");     this.shutdown().await;     println!(\"Done, thx :)\");     std::process::exit(0); }); } }  <\/code><\/pre>\n<p>\u0422\u0443\u0442 \u044e\u0437\u0430\u0435\u043c \u0441\u0438\u0433\u043d\u0430\u043b\u044b \u0438 \u0442\u0430\u0439\u043c\u0430\u0443\u0442-\u043e\u0431\u0435\u0440\u0442\u043a\u0443 \u043d\u0430\u0434 \u0444\u044c\u044e\u0447\u0435\u0440\u0441\u0430\u043c\u0438 \u0438\u0437 \u0442\u043e\u043a\u0438\u043e, \u0447\u0443\u0442\u044c-\u0447\u0443\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 (\u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435\u043c \u0432\u0441\u0435\u0445 \u0442\u0430\u0441\u043e\u043a \u0438\u0437 \u043e\u0447\u0435\u0440\u0435\u0434\u0438) \u0438 \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435 \u0432\u0441\u0435 \ud83d\ude42<\/p>\n<p>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0434\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440: \u0443\u0447\u0435\u0431\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0435 \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u0435\u0442 (\u0438 \u043d\u0435 \u0445\u043e\u0447\u0435\u0442 \u043f\u043e\u043a\u0440\u044b\u0432\u0430\u0442\u044c) \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u044b &#8212; \u0447\u0442\u043e \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0431\u043b\u0435\u0433\u0447\u0430\u0435\u0442 \u043a\u0430\u043a \u0447\u0442\u0435\u043d\u0438\u0435, \u0442\u0430\u043a \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e. \u0427\u0438\u0442\u0430\u0442\u0435\u043b\u044c, \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u0439 \u043e\u0446\u0435\u043d\u0438\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0442\u0435\u043c\u044b \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0430\u0435\u0442\u0441\u044f \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 cppCrow.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 3: \u041e\u0431\u043c\u0435\u0440\u043a\u0438<\/h3>\n<p>\u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043c\u0435\u0440\u0438\u0442\u044c\u0441\u044f: c\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c &#171;hello world&#187; \u0438 &#171;\u0434\u0432\u0430 \u043f\u043b\u044e\u0441 \u0434\u0432\u0430&#187; \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u0438\u0437 \u0443\u0440\u043b\u0430. \u0414\u043e\u0431\u0430\u0432\u0438\u043c nodejs (\u0432\u0435\u0440\u0441\u0438\u0438 20) \u0437\u0430 \u0431\u0430\u0437\u0443 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f (\u0440\u0435\u0431\u044f\u0442\u0430 \u0438\u0437 crowCpp \u0433\u043e\u0432\u043e\u0440\u044f\u0442, \u0447\u0442\u043e \u0440\u0432\u0443\u0442 \u043d\u043e\u0434\u0443 \u0432 \u0445\u043b\u0430\u043c). \u041d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c, \u0447\u0442\u043e \u0443\u0447\u0435\u0431\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u0433\u043e\u0442\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0434\u0430\u043a\u0448\u043d-\u0440\u0435\u0448\u0435\u043d\u0438\u044f. \u0421\u0447\u0438\u0442\u0430\u0435\u043c \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e (\u0434\u043b\u044f \u043b\u044e\u0431\u0438\u0442\u0435\u043b\u0435\u0439 \u0442\u043e\u0447\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0440\u0435\u043f\u0435 cppCrow \u0435\u0441\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0435 \u0431\u0435\u043d\u0447\u043c\u0430\u0440\u043a\u0438) \u0438 (\u0435\u0449\u0435 \u0440\u0430\u0437) \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e nodejs.<\/p>\n<p><code>ab -n 32768 -c 128 \"http:\/\/0.0.0.0:18080\/\"<\/code><\/p>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 &#171;\u0426\u044d&#187;<br \/> <code>-c concurrency\u00a0 Number of multiple requests to make at a time<\/code><\/p>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b:<\/p>\n<pre><code>nodejs c=128 -&gt; OK nodejs c=256 -&gt; Err  candidate c=128 -&gt; OK candidate c=256 -&gt; OK candidate c=512 -&gt; Err  canditate without timeout c=512 -&gt; OK canditate without timeout c=625 -&gt; OK canditate without timeout c=725 -&gt; Err  cppCrow c=128 -&gt; OK cppCrow c=256 -&gt; OK cppCrow c=512 -&gt; OK cppCrow c=725 -&gt; OK cppCrow c=1024 -&gt; Err <\/code><\/pre>\n<p>\u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c \u0447\u0442\u043e \u043e\u0431\u0435\u0440\u0442\u043a\u0430 timeout \u0442\u0430\u043a \u043d\u0435\u0445\u0438\u043b\u043e \u0441\u044c\u0435\u0434\u0430\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c.<\/p>\n<p>\u041a\u043e\u0434 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432:<\/p>\n<pre><code class=\"javascript\">app.get('\/', (req, res) =&gt; {   \u00a0\u00a0res.send('Hello World!')   })      app.get('\/:a\/plus\/:b', (req, res) =&gt; {   \u00a0\u00a0let a = Number(req.params.a)   \u00a0\u00a0let b = Number(req.params.b)   \u00a0\u00a0res.send(`${a+b}`)   })    const port = 18080 app.listen(port, () =&gt; {   \u00a0\u00a0console.log(`Example app listening on port ${port}`)   }) <\/code><\/pre>\n<pre><code class=\"cpp\">int main() {     crow::SimpleApp app;      CROW_ROUTE(app, \"\/\")([](){         return \"Hello world\";     });      CROW_ROUTE(app,\"\/&lt;int&gt;\/plus\/&lt;int&gt;\")     ([](int a, int b){         std::ostringstream os;         os &lt;&lt; a+b;         return crow::response(os.str());     });      app.port(18080).multithreaded().run(); } <\/code><\/pre>\n<pre><code class=\"rust\">#[tokio::main] async fn main() -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; {     let addr = env::args()         .nth(1)         .unwrap_or_else(|| \"0.0.0.0:18080\".to_owned());          let mut app = SimpleApp::default();          route![app, \"\/\", || \"Hello world\".to_owned()];          route![app, \"&lt;usize&gt;\/plus\/&lt;usize&gt;\", |a,b,_req| {          use RouteTokens::Usize;         match (a,b) {             (Usize(x), Usize(y)) =&gt; format!(\"{}\", x+y),             _ =&gt; panic!(\"hmm...\"),         }     }];      app.start(&amp;addr).await?;     Ok(()) }  <\/code><\/pre>\n<p>\u0421\u0430\u043c\u044b\u0439 \u043b\u0435\u0433\u043a\u0438\u0439 \u0438\u0442\u043e\u0433: \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u0432\u0437\u0433\u043b\u044f\u043d\u0443\u0442\u044c \u043d\u0430 \u0441\u0442\u0435\u043a \u0442\u043e\u043a\u0438\u043e, \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0432\u0430\u0441 \u0442\u043e\u0436\u0435 \u0432\u0434\u043e\u0445\u043d\u043e\u0432\u0438\u0442 \u043f\u043e\u0438\u0437\u0443\u0447\u0430\u0442\u044c \u043d\u0430 \u0434\u043e\u0441\u0443\u0433\u0435 \u043a\u0430\u043a\u043e\u0439-\u043b\u0438\u0431\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u043a \ud83d\ude42<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/874760\/\"> https:\/\/habr.com\/ru\/articles\/874760\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0420\u0430\u0441\u0442 \u0445\u043e\u0440\u043e\u0448, \u0432\u0441\u0435 \u044d\u0442\u043e \u0437\u043d\u0430\u044e\u0442. \u0418\u043d\u0432\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0448\u044c \u0432\u0440\u0435\u043c\u044f \u0432 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043a\u0430\u0439\u0444\u0443\u0435\u0448\u044c, \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0448\u044c c \u0440\u0438\u0441\u043a\u0430\u043c\u0438, \u0437\u0430\u0434\u0430\u0435\u0448\u044c\u0441\u044f \u0432\u043e\u043f\u0440\u043e\u0441\u043e\u043c &#8212; \u0430 \u043c\u043e\u0436\u0435\u0442, \u0440\u0430\u0441\u0442 \u0435\u0449\u0435 \u043a\u0440\u0443\u0447\u0435? \u041f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0435 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u043b\u0438\u0434\u043d\u044b\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u0430 \u043f\u043b\u044e\u0441\u0430\u0445 (5k \u0437\u0432\u0435\u0437\u0434 \u043d\u0430 \u0433\u0438\u0442\u0445\u0430\u0431\u0435) &#8212; \u0438 \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e. \u0412\u0440\u043e\u0434\u0435, \u0432\u0441\u0435 \u0442\u0430\u043a \u0434\u0435\u043b\u0430\u044e\u0442, \u043d\u043e \u043c\u043e\u0436\u0435\u0442, \u0441\u0443\u0442\u044c \u0432 \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u0438 \u0438\u0434\u0435\u0439, \u0430 \u043d\u0435 \u043a\u043e\u0434\u0430. \u0411\u044b\u0442\u044c \u043c\u043e\u0436\u0435\u0442, \u043c\u044b \u043d\u0430\u0439\u0434\u0435\u043c \u043e\u0442\u0432\u0435\u0442\u044b \u043e \u0432\u044b\u0440\u0430\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u044f\u0437\u044b\u043a\u0430, \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u0438 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0430\u043c \u0441\u0442\u0430\u043d\u0435\u0442 \u044f\u0441\u043d\u043e &#8212; \u0430 \u0434\u0440\u0443\u0433 \u043b\u0438 \u043d\u0430\u0448 \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440, \u043d\u043e \u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u043c\u044b \u043d\u0430\u0441\u043b\u0430\u0434\u0438\u043c\u0441\u044f \u044d\u0441\u0442\u0435\u0442\u0438\u043a\u043e\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u0440\u0430\u0441\u0442e.<\/p>\n<p>\u0421\u0442\u0440\u0430\u043d\u0430 \u0431\u043e\u0433\u0430\u0442\u0430 \u0438\u0434\u0435\u044f\u043c\u0438, \u043a\u0430\u043a \u0447\u0438\u0442\u0430\u0442\u044c \u043a\u043e\u0434: \u0431\u043b\u043e\u043a-\u0441\u0445\u0435\u043c\u044b, \u043a\u043e\u043d\u0446\u0435\u043f\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u043e\u0434\u0435\u043b\u0438, \u0444\u0430\u0439\u043b \u0447\u0435\u0440\u0435\u0437 \u0444\u0430\u0439\u043b \u0438 \u0442.\u0434. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0440\u0430\u0431\u043e\u0447\u0438\u0439 \u0434\u043b\u044f \u043c\u0435\u043d\u044f \u043c\u0435\u0442\u043e\u0434 &#8212; \u044d\u0442\u043e \u0447\u0442\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u043f\u043e\u0434\u0440\u044f\u0434. \u042f \u0432\u044b\u0431\u0440\u0430\u043b \u0442\u0435\u043c\u0443, \u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u0441\u043b\u044b\u0448\u0430\u043b\u0438 \u0442\u043e\u0447\u043d\u043e (\u0445\u043e\u0442\u044f \u0431\u044b \u043a\u0440\u0430\u0435\u043c \u0443\u0445\u0430): \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0414\u0430\u043b\u0435\u0435 \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 \u0431\u0443\u0434\u0435\u043c \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0443\u0441\u0442\u0440\u043e\u0435\u043d \u0432\u0435\u0431 \u0441\u0435\u0440\u0432\u0435\u0440 crowCpp (\u0441\u0441\u044b\u043b\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0438\u0436\u0435) \u0438 \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c (\u0441\u043a\u043e\u0440\u0435\u0435 \u0432\u043e\u043f\u043b\u043e\u0449\u0430\u0442\u044c \u0435\u0433\u043e \u0438\u0434\u0435\u0438) \u043d\u0430 \u044f\u0437\u044b\u043a \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0441\u0442.<\/p>\n<p>\u041e\u0447\u0435\u043d\u044c \u043a\u0440\u0430\u0442\u043a\u043e \u0437\u0430\u043c\u0435\u0442\u043a\u0438 \u043d\u0430 \u043f\u043e\u043b\u044f\u0445 \u043f\u043e \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044e (<a href=\"https:\/\/github.com\/CrowCpp\/Crow\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/CrowCpp\/Crow<\/a>):<\/p>\n<p>http_request.h &#8212; \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u043a\u043e\u0434, \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438\/\u043c\u0435\u0442\u043e\u0434\u044b, \u043c\u043d\u043e\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0431\u0435\u0437 \u0434\u043e\u043a\u043e\u0432 \u0444\u0438\u0433 \u0440\u0430\u0437\u0431\u0435\u0440\u0435\u0448\u044c, \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0438\u043b\u0438 \u043d\u0435\u0442).<\/p>\n<p>http_response.h &#8212; \u043c\u043d\u043e\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u043e\u0432 std::move, \u043f\u0440\u0438 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u043d\u0435 \u043f\u0440\u0435\u0434\u0443\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043d\u044b\u0445 \u043b\u043e\u0433\u0438\u043a\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b &#8212; \u043b\u043e\u0433\u0438\u0440\u0443\u0435\u043c \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043c\u043d\u043e\u0433\u043e \u043c\u0443\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430, \u0444\u043b\u0430\u0433\u043e\u0432\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0442.\u0434.<\/p>\n<p>http_connection.h &#8212; \u043f\u0440\u0438\u0432\u0435\u0442, \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u044f (\u0432 \u043f\u0440\u0438\u0440\u043e\u0434\u0435 \u043f\u043e\u043a\u0430 \u0435\u0449\u0435 \u043d\u0435\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0431\u0435\u0437 \u0440\u0435\u043a\u0443\u0440\u0441\u0438\u0438 \ud83d\ude42<\/p>\n<p>http_server.h &#8212; \u043f\u0435\u0440\u0435\u0438\u0437\u043e\u0431\u0440\u0435\u0442\u0435\u043d\u0438\u0435 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u043e\u0432 \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0438 \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438 (load balancing) \u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0435\u043c &#171;\u0442\u0443\u0434\u0443&#187;, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0435\u0449\u0435 \u043f\u0430\u0440\u0443 \u0431\u0430\u0439\u0442.<\/p>\n<p>app.h &#8212; \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0438 \u043c\u0430\u043a\u0440\u043e\u0441\u044b.<br \/> socket_adaptors.h &#8212; \u043e\u0431\u0435\u0440\u0442\u043a\u0430 \u043d\u0430\u0434 \u0441\u043e\u043a\u0435\u0442\u043e\u043c.<\/p>\n<p>routing.h &#8212; \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u043c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043a\u043e\u0434\u0430:<\/p>\n<pre><code class=\"cpp\">void handle_upgrade(...) override {     max_payload_ = max_payload_override_ ? max_payload_ : app_-&gt;websocket_max_payload();     new crow::websocket::Connection&lt;SocketAdaptor, App&gt;(req, std::move(adaptor), app_, max_payload_, ...); } <\/code><\/pre>\n<p>\u041d\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 \u044f\u0432\u0443, \u043d\u043e \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 websocket::Connection \u0441\u0430\u043c \u0441\u0435\u0431\u044f \u0438 \u043f\u043e\u0434\u0447\u0438\u0449\u0430\u0435\u0442<\/p>\n<pre><code class=\"cpp\">... adaptor_.close(); handler_-&gt;remove_websocket(this); delete this; <\/code><\/pre>\n<p>\u0435\u0449\u0435_\u043c\u043d\u043e\u0433\u043e_\u0444\u0430\u0439\u043b\u043e\u0432.h &#8212; \u043c\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u0444\u0438\u0447\u0435\u0439, \u043d\u043e \u0432 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0435, \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u043f\u0440\u043e\u0442\u043e\u0442\u0438\u043f \u0440\u0430\u0431\u043e\u0447\u0435\u0433\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<h3>\u0427\u0430\u0441\u0442\u044c 1: \u041f\u0438\u043d\u0433-\u041f\u043e\u043d\u0433<\/h3>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0434\u043e\u043b\u0433\u043e\u0433\u043e \u0438 \u0443\u043f\u043e\u0440\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u043f\u0438\u0442\u0438\u044f \u043a\u0440\u0435\u043f\u043a\u043e\u0433\u043e \u043a\u043e\u0444\u0435, \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 \u043e \u0434\u043e\u0442\u0435, \u0448\u0430\u0445\u043c\u0430\u0442\u0430\u0445 \u0438 \u0441\u043d\u0443\u043a\u0435\u0440\u0435, \u0435\u0449\u0435 \u0438 \u0442\u0435\u043b\u0435\u0433\u0438 (\u0442\u0443\u0442 \u043d\u0438\u043a\u0443\u0434\u0430) &#8212; \u0434\u0438\u0437\u0430\u0439\u043d\u0438\u043c \u043d\u0430 \u0441\u0430\u043b\u0444\u0435\u0442\u043a\u0435 \u043f\u0440\u043e\u0435\u043a\u0442: \u0441\u043e\u043a\u0435\u0442 -&gt; \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d -&gt; \u0441\u0435\u0440\u0432\u0435\u0440 -&gt; \u0430\u043f\u043f (\u0440\u0435\u0441\u043f\u043e\u043d\u0441 \u0438 \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u0433\u0434\u0435-\u0442\u043e \u0441\u0431\u043e\u043a\u0443, \u0440\u043e\u0443\u0442\u0435\u0440 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u0430\u043f\u043f).<\/p>\n<p>\u041a\u0430\u043a-\u0442\u043e \u0442\u0430\u043a, \u0435\u0449\u0435 \u0440\u0430\u0437: \u0430\u043f\u043f\u043b\u0438\u043a\u0435\u0439\u0448\u043d -&gt; \u0441\u0435\u0440\u0432\u0435\u0440 -&gt; \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d -&gt; \u0441\u043e\u043a\u0435\u0442. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043a\u043e\u043d\u0446\u043e\u0432, \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432\u0438\u0434\u0435\u0442\u044c \u0442\u0430\u043a\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441:<\/p>\n<pre><code class=\"rust\">route![app, \"\/\", || \"Hello world\".to_owned()]; route![app, \"\/measure\/&lt;float&gt;\/and\/&lt;int&gt;\", |x,y,_req| format!(\"{:?} and {:?}\" x, y)]; <\/code><\/pre>\n<p>\u0425\u043e\u0434\u044f\u0442 \u0441\u043b\u0443\u0445\u0438, \u0447\u0442\u043e \u043c\u0438\u0433\u0440\u0430\u0446\u0438\u044e \u043a\u043e\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442 \u0441\u0442\u0440\u043e\u0447\u043a\u0430 \u0437\u0430 \u0441\u0442\u0440\u043e\u0447\u043a\u043e\u0439 \u0441pp -&gt; rust, \u0430 \u043c\u043e\u0436\u043d\u043e \u0438 \u043c\u0438\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043d\u0443\u043b\u044f, \u0445\u043e\u0442\u044f, \u043a\u0430\u043a \u0441\u043a\u0430\u0437\u0430\u043b \u0431\u044b \u0414\u0436\u043e\u044d\u043b\u044c \u0421\u043f\u043e\u043b\u044c\u0441\u043a\u0438 &#8212; \u0431\u0443\u0434\u0443\u0442 \u0431\u0430\u0433\u0438, \u0434\u0430 \u0438 \u0444\u0438\u0433 \u0441 \u043d\u0438\u043c\u0438, \u043f\u0440\u043e\u0435\u043a\u0442-\u0442\u043e \u0443\u0447\u0435\u0431\u043d\u044b\u0439. \u0422\u0430\u043a\u0436\u0435 \u0432\u0435\u0431\u0441\u043e\u043a\u0435\u0442\u044b \u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0438\u0442\u044c \u043d\u0435 \u0431\u0443\u0434\u0435\u043c\/\u0445\u043e\u0442\u0438\u043c, \u0438 \u0432\u0435\u0440\u0441\u0438\u044e \u0445\u0442\u0442\u043f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0442\u043e\u043b\u044c\u043a\u043e 1.1. \u0412\u0441\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u0432\u0435\u043b\u0438\u043a\u043e\u043b\u0435\u043f\u043d\u044b\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0438 \u0441 \u0431\u0435\u0447\u043c\u0430\u0440\u043a\u0430\u043c\u0438, \u043d\u043e \u0445\u043e\u0442\u044c \u043a\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0441\u043a\u0430\u0437\u0430\u043b \u0431\u044b &#8212; \u0437\u043d\u0430\u0435\u0442\u0435, \u0431\u0435\u0447\u043c\u0430\u0440\u043a\u0438 \u0443 \u043d\u0430\u0441 \u043d\u043e\u0440\u043c\u0443\u043b\u044c, \u0430 \u043a\u043e\u0434 \u0435\u0449\u0435 \u043b\u0443\u0447\u0448\u0435 &#8212; \u0442\u0443\u043f\u043e \u0447\u0438\u0442\u0430\u0435\u043c, \u0434\u0430 \u0438 \u0441 \u0444\u043b\u0430\u0433\u0430\u043c\u0438 (\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430 300) \u043c\u044b \u043d\u0435 \u0431\u0430\u043b\u0443\u0435\u043c\u0441\u044f.<\/p>\n<p>\u041a\u043e\u043d\u043d\u0435\u043a\u0448\u043d.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ connection.rs  pub struct Connection { socket: Socket, }  impl Connection { pub fn new(stream: TcpStream) -&gt; Self { Connection { socket: Socket::new(stream), } } }  impl Connection{ pub async fn start(&amp;mut self, app: &amp;App) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; { let s = self.socket.read_all().await?; if !s.is_empty() { let req = Parser::new(s).parse().ok_or(\"failed to parse\")?; let resp = app.handle(req).await;         self.socket.write_all(resp).await?;     }     Ok(()) } } <\/code><\/pre>\n<p>\u0414\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c \u0441 \u0440\u0430\u0441\u0442\u043e\u043c: 1) \u0444\u044c\u044e\u0447\u0435\u0440\u0441\u044b \u0431\u0435\u0437 await \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0435\u043b\u0430\u044e\u0442, 2) \u0437\u043d\u0430\u043a\u0438 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 &#8212; \u0435\u0441\u0442\u044c \u043d\u0435\u044f\u0432\u043d\u0430\u044f \u0440\u0430\u0441\u043f\u0430\u043a\u043e\u0432\u043a\u0430 Result \u0438\u043b\u0438 Option.<\/p>\n<p>\u041f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0438\u0439 \u0438\u0437 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u043f\u0430\u0440\u0441\u0435\u0440\u043e\u0432 \u0445\u0442\u0442\u043f \u0437\u0430\u043f\u0440\u043e\u0441\u0430<\/p>\n<pre><code class=\"rust\">\/\/\/ parser.rs  pub struct Parser&lt;'a&gt; { s: &amp;'a str, }  impl &lt;'a&gt; Parser&lt;'a&gt; { pub fn new(s: &amp;'a str) -&gt; Self { Parser { s } } }  impl Parser&lt;'_&gt; { pub fn parse(self) -&gt; Option&lt;Request&gt; { let (mut info, mut headers) = (vec![], vec![]);  let mut iter = self.s.split(\"\\r\\n\"); for x in iter.next()?.split(' ') {  info.push(x);  } for x in iter.by_ref() { if x.is_empty() { break; } let mut b = x.split(\": \"); headers.push(( b.next()?.to_owned(),  b.next()?.to_owned() )); } let body = iter.next()?.to_owned();  Request::build(info, headers, body) } }  <\/code><\/pre>\n<p>\u0414\u0432\u0430 \u043c\u043e\u043c\u0435\u043d\u0442\u0430: 1) \u043c\u0435\u0442\u043e\u0434 parse \u043f\u043e\u0433\u043b\u043e\u0442\u0438\u0442 \u043e\u0431\u044c\u0435\u043a\u0442 (self \u0431\u0435\u0437 \u0430\u043c\u043f\u0435\u0440\u0441\u0430\u043d\u0434\u0430) &#8212; \u0433\u0443\u0434 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438; 2) lifetime (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u043f\u043e\u0441\u0442\u0440\u043e\u0444) \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u044e\u0437\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0431\u0443\u0444\u0435\u0440 \u0441\u043e\u043a\u0435\u0442\u0430 (\u0447\u0435\u0440\u0435\u0437 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443) \u043f\u043e\u0441\u043b\u0435 \u0435\u0433\u043e (\u0431\u0443\u0444\u0435\u0440\u0430) \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f.<\/p>\n<p>\u0420\u0435\u043a\u0432\u0435\u0441\u0442.pc &#8212; \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u043c\u0443 \u043a\u043e\u0434\u0443.<\/p>\n<pre><code class=\"rust\">\/\/\/ request.rs  #[derive(Default, Debug, Clone)] pub struct Request { pub method: String, pub url: String, pub version: String, pub query: String, pub headers: Vec&lt;(String, String)&gt;, pub body: String,   }  fn parse_url(s: &amp;str) -&gt; (String, String) { if let Some(i) = s.find('?') { (s[..i].to_owned(), s[i+1..].to_owned()) } else { (s.to_owned(), \"\".to_owned()) } }  impl Request { pub fn build(mut info: Vec&lt;&amp;str&gt;, headers: Vec&lt;(String, String)&gt;, body: String) -&gt; Option&lt;Self&gt; { let version = info.pop()?.to_owned(); let (url, query) = parse_url(info.pop()?); let method = info.pop()?.to_owned(); Some(Request {method, url, query, version, headers, body}) } } <\/code><\/pre>\n<p>\u0420\u0435\u0441\u043f\u043e\u043d\u0441 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0441\u0442\u0440\u0438\u043d\u0433\u043e\u043c (String).<\/p>\n<p>\u0412\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u0441\u043e\u043a\u0435\u0442\u0430\u043c &#8212; \u0421\u043e\u043a\u0435\u0442.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ socket.rs  pub struct Socket { stream: TcpStream, buf: [u8; 1024], }  impl Socket { pub fn new(stream: TcpStream) -&gt; Self {     Socket { stream, buf: [0; 1024] } } }  impl Socket {  pub async fn read_all(&amp;mut self) -&gt; Result&lt;&amp;str, Box&lt;dyn Error&gt;&gt; { let n = self.stream.read(&amp;mut self.buf).await?; Ok(std::str::from_utf8(&amp;self.buf[..n])?) }  pub async fn write_all(&amp;mut self, s: String) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; { let x = format!(\"HTTP\/1.1 200 OK\\r\\nContent-Length: {}\\r\\n\\n\", s.len()); self.stream.write_all(&amp;x.into_bytes()).await?; self.stream.write_all(&amp;s.into_bytes()).await?; Ok(()) } } <\/code><\/pre>\n<p>\u041f\u0430\u0440\u0443 \u043c\u043e\u043c\u0435\u043d\u0442\u043e\u0432: 1) \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c, \u0447\u0442\u043e \u0431\u0443\u0444\u0435\u0440 \u0432\u043c\u0435\u0441\u0442\u0438\u0442 \u0432\u0435\u0441\u044c \u0440\u0435\u043a\u0432\u0435\u0441\u0442 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445, 2) \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u043c \u0431\u0443\u0444\u0435\u0440 \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0441\u043e\u043a\u0435\u0442\u043e\u043c \u0438\u0437-\u0437\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438, 3) \u0440\u0430\u0437\u043c\u0435\u0440 \u0431\u0443\u0444\u0435\u0440\u0430 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b, 4) \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0445\u0435\u0434\u0435\u0440\u0430.<\/p>\n<p>\u0421\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435 &#8212; \u0421\u0435\u0440\u0432\u0435\u0440.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ server.rs  pub struct Server { listener: TcpListener, }  impl Server { pub async fn bind(addr: &amp;str) -&gt; Result&lt;Server, Box&lt;dyn Error&gt;&gt; { let listener = TcpListener::bind(&amp;addr).await?;     println!(\"Listening on: {addr}\");     Ok(Server{listener}) }  pub async fn accept(&amp;mut self, app: &amp;'static App) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; { loop { let (stream, _) = self.listener.accept().await?; tokio::spawn(async move { let mut p = Connection::new(stream); p.start(app).await.unwrap(); }); } } } <\/code><\/pre>\n<p>\u0420\u0435\u0431\u044f\u0442\u0430 \u0438\u0437 CrowCpp \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u0441\u0432\u043e\u0439 (\u043d\u0430 \u0431\u0430\u0437\u0435 boost::asio) \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u0449\u0438\u043a \u043d\u0430\u0433\u0440\u0443\u0437\u043a\u0438, \u0443 \u0440\u0430\u0441\u0442\u0430 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0432\u0435\u0441\u0435\u043b\u0435\u0435 &#8212; \u0435\u0441\u0442\u044c tokio \u0440\u0430\u043d\u0442\u0430\u0439\u043c. \u042d\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u0440\u0430\u043d\u0442\u0430\u0439\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0435\u0440\u0435\u0442 \u043d\u0430 \u0441\u0435\u0431\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0446\u0438\u044e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0442\u0430\u0441\u043a\u043e\u0432, \u0431\u0430\u043b\u0430\u043d\u0441\u0438\u0440\u043e\u0432\u043a\u0443 (\u0441\u0430\u043c\u0443\u044e \u0431\u0430\u0437\u043e\u0432\u0443\u044e) \u0438 \u0442.\u0434.<\/p>\n<p>\u0418\u0437 \u0434\u043e\u043a\u043e\u0432 tokio::spawn<br \/> <code>Spawning a task enables the task to execute concurrently to other tasks. The spawned task may execute on the current thread, or it may be sent to a different thread to be executed.<\/code><\/p>\n<p>\u0415\u0449\u0435 \u0434\u043e\u043a\u0438 \u043e \u0442\u043e\u043a\u0438\u0439\u0441\u043a\u043e\u043c \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0435:<br \/> <code>The multi-thread scheduler executes futures on a\u00a0thread pool, using a work-stealing strategy. By default, it will start a worker thread for each CPU core available on the system. This tends to be the ideal configuration for most applications.<\/code><\/p>\n<p>\u0422\u0430\u0441\u043a\u0438 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u0430 \u043d\u0435 \u043b\u044e\u0431\u044f\u0442 \u0431\u0440\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438\u0437\u0432\u043d\u0435, \u0438 \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0430\u043f\u043f\u0435 \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0438\u0442\u0432\u043e\u0440\u0438\u0442\u044c\u0441\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c (\u0441\u043c. \u0432 \u043a\u043e\u0434\u0435 &#8212; \u0441\u0442\u0430\u0442\u0438\u043a \u0441\u0441\u044b\u043b\u043a\u0430 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u0430\u0432\u043d\u0430 \u0432\u044d\u043b\u044c\u044e \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432) \u0438 \u043f\u0435\u0440\u0435\u043f\u0440\u044b\u0433\u043d\u0443\u0442\u044c \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u0443\u044e \u0442\u0430\u0441\u043a\u0443. \u0418\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d\u0430 \u0432\u0437\u044f\u043b \u0443 \u0440\u0435\u0431\u044f\u0442 \u0438\u0437 CrowCpp, \u043f\u043e\u0447\u0435\u043c\u0443-\u0442\u043e \u0442\u0430\u043a \u0438 \u043d\u0435 \u0441\u043c\u043e\u0433 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u043d\u0438\u0447\u0435\u0433\u043e \u043b\u0443\u0447\u0448\u0435 \ud83d\ude42<\/p>\n<p>\u0426\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043a\u0430 &#8212; a\u043f\u043f.\u0440\u0441<\/p>\n<pre><code class=\"rust\">\/\/\/ app.rs  #[derive(Default)] pub struct App { map: Trie&lt;fn(Request, Vec&lt;RouteTokens&gt;) -&gt; String&gt;, }  unsafe fn make_static&lt;T&gt;(t: &amp;T) -&gt; &amp;'static T {     std::mem::transmute(t) }  impl App { pub async fn start(&amp;self, addr: &amp;str) -&gt; Result&lt;(), Box&lt;dyn Error&gt;&gt; {     let mut server = Server::bind(addr).await?;     \/\/ safe: app should be alive before termination     server.accept(unsafe { make_static(self) }).await?;     Ok(()) }  pub async fn handle(&amp;self, req: Request) -&gt; String { let b = req.url.split('\/').filter(|s| !s.is_empty()); self.map.get(b) .map(|(fun, args)| fun(req, args)) .unwrap_or(\"Not found\".to_owned()) }  pub fn service(&amp;mut self, key: &amp;'static str, fun: fn(Request, Vec&lt;RouteTokens&gt;) -&gt; String) { let b = key.split('\/').filter(|s| !s.is_empty()); self.map.insert(b, fun); } } <\/code><\/pre>\n<p>\u0422\u0443\u0442 \u044e\u0437\u0430\u0435\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043d\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e (Trie, \u043d\u0443\u0436\u043d\u043e\u0435 \u0434\u043b\u044f \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u0432), \u0447\u0443\u0442\u044c-\u0447\u0443\u0442\u044c unsafe \u043a\u043e\u0434\u0430 (\u0438 \u043a\u043e\u043c\u043c\u0435\u043d\u0442, \u043f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e OK) \u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439 \u0442\u0438\u043f\u043e\u0432: 1) fn(&#8230;) &#8212; \u0435\u0441\u0442\u044c non-capturing\u00a0closures, \u0442\u043e \u0435\u0441\u0442\u044c \u043b\u0430\u043c\u0431\u0434\u0435 \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0442 \u0437\u0430\u0445\u0432\u0430\u0442\u0438\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442 \u0438\u0437\u0432\u043d\u0435, 2) key &amp;&#8217;static str &#8212; \u043f\u0443\u0442\u044c \u0432 \u0440\u043e\u0443\u0442\u0435\u0440\u0435 \u043f\u0438\u0448\u0435\u043c (\u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432) \u0440\u0443\u0447\u043a\u0430\u043c\u0438 (\u0445\u0437, \u0445\u043e\u0440\u043e\u0448\u043e \u044d\u0442\u043e \u0438\u043b\u0438 \u043f\u043b\u043e\u0445\u043e, \u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430).<\/p>\n<p>\u041f\u0440\u0435\u0444\u0438\u043a\u0441\u043d\u043e\u0435 \u0434\u0435\u0440\u0435\u0432\u043e (\u043e\u043f\u044f\u0442\u044c \u0436\u0435, \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f \u0438\u043c\u043f\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f)<\/p>\n<pre><code class=\"rust\">\/\/\/ trie.rs  pub struct Trie&lt;T&gt; { head: Node&lt;T&gt;,  }  struct Node&lt;T&gt; { value: Option&lt;T&gt;, map: HashMap&lt;&amp;'static str, Node&lt;T&gt;&gt;  }  impl&lt;T&gt; Default for Trie&lt;T&gt; { fn default() -&gt; Self { let head = Node { value: None, map: HashMap::new() }; Trie { head } } }  impl&lt;T&gt; Trie&lt;T&gt; { pub fn insert(&amp;mut self, v: impl IntoIterator&lt;Item = &amp;'static str&gt;, elem: T) { let mut node = &amp;mut self.head; for s in v { if node.map.contains_key(s) {  node = node.map.get_mut(s).unwrap(); } else { let next = Node { value: None, map: HashMap::new() }; node.map.insert(s, next); node = node.map.get_mut(s).unwrap();  } } node.value = Some(elem); }  pub fn get&lt;'a&gt;(&amp;self, v: impl IntoIterator&lt;Item = &amp;'a str&gt;) -&gt; Option&lt;(&amp;T, Vec&lt;RouteTokens&gt;)&gt; { let mut node = &amp;self.head; let mut args = vec![]; for s in v { let (s, token) = mapping(s); if node.map.contains_key(s) {  node = node.map.get(s).unwrap(); } else { return<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-445438","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/445438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=445438"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/445438\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=445438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=445438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=445438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}