atom-0.4.0/.cargo_vcs_info.json0000644000000001121373702321500120700ustar00{ "git": { "sha1": "2efac720e702c6f8b04a67e4a5bf27b456a46050" } } atom-0.4.0/.gitignore010066400017500001750000000000221373702275600126740ustar0000000000000000target Cargo.lock atom-0.4.0/.travis.yml010066400017500001750000000015061373702275600130250ustar0000000000000000language: rust rust: - stable - beta - nightly env: global: - secure: l8hKyZzEGNBE/j44xOFJS04MRM1icLvBMT5QK6sujJ+wN9X/jE4pBDLuL3ByajnQyspJOgqvNvYkMchQGKW7Aqan+VorKGk/CFf7+ly3Dpeitq/tNTZdu454kKGvMWfU7a2ETVHg19uN5Lo9p40tWiTTYJ+0lt8tK+AEkAriLbs= script: - cargo build - cargo test - cargo doc after_script: - mv target/doc doc - curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh cache: cargo matrix: fast_finish: true include: - rust: nightly-2018-05-06 env: # use env so updating versions causes cache invalidation - CLIPPY_VERSION=0.0.197 before_script: - rustup component add rustfmt-preview - cargo install clippy --version $CLIPPY_VERSION || echo "clippy already installed" script: - cargo fmt -- --write-mode=check - cargo clippy atom-0.4.0/Cargo.lock0000644000000002071373702321500100500ustar00# This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "atom" version = "0.4.0" atom-0.4.0/Cargo.toml0000644000000013501373702321500100730ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "atom" version = "0.4.0" authors = ["Colin Sherratt "] description = "A safe abstraction around AtomicPtr" homepage = "https://github.com/slide-rs/atom" license = "Apache-2.0" atom-0.4.0/Cargo.toml.orig010066400017500001750000000003331373702275600136000ustar0000000000000000[package] name = "atom" version = "0.4.0" authors = ["Colin Sherratt "] license = "Apache-2.0" homepage = "https://github.com/slide-rs/atom" description = "A safe abstraction around AtomicPtr" atom-0.4.0/LICENSE010066400017500001750000000236361373702275600117310ustar0000000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. atom-0.4.0/assets/load.png010066400017500001750000000540701373702275600136470ustar0000000000000000PNG  IHDR"sRGB pHYs (iTXtXML:com.adobe.xmp 5 2 1 2@IDATx\E'EAT) "*(H@D" C^C5N do:{w{޽n;O[yM.ŀO$]~̵X8Z@Vi! Jya.yScK/vǵmiԟagp΀O UKHIqK+ţۑRggꖦe<i.oas*c1E:n<77{g>T.Q &K /2"|ٴ]v.VZ[ݺu{gcتaص0̟u w;Z\:oyn^pꒁuyU~QmFpX~¯ 5[ǀ) V3 S3Hh{3Fhs+oewptKW;l\ +´|~;fiO / c o쨈]ޙe/RN K _ ̯++)|#''geE'0n YKPOT* aJ. \[*K*p0s䚊8J6T~.ŠX8΀3P ] SPpEأkQ%Y]+7`|VwjT2~6pw={v޽{Ϛ0aB5X#*ZnǏ_\ ,/۠3fŋ.h \uUWyWğ.?i7nܖi:ÇoꫯbTc= qUVYe/oϞ=kl23qwymf͚ճ_==83s:6\rɵ{tx^{7h~{>&mG}t\p3ðav~ѣGy;}Whךko o?\;v9=Et[yW4iRZq{,]Ô|8O@(ugu u΀)+CMvCc9&HAץx6`7>m7 %(u"%']bEDʠʎQP/⮋-o̘1#̜93H21u7߄y'z95y ##s:L6-'X)/իX0} c%=AFB<ԅ: 0h:yѣGaP4 >nḭ]lL0T3 T3FJrSRFHTXX&&z#\O7PNn'E~ H$b\7![sc4%R h.BiHsa2 ,FJs\]0R˃X zd-_ *p2HuL91I ?.\gvQTR 9<ꯍg}SCV.u{gW@?,΀3 Tg) SDc|Յ˥QV)Gm'R nf@Җ6q{ ?##x@}׵]#X[{o\gp7gl"bBlb%?K3=#UTi{)/~?l5Ms܆ V 79mmsƸ!\T_||È3 T7DBcbMBSRpmbE˥iw O3H w&^m\6[lqۏcy]zqj'i 8e3B^ ).L`]T)+*ɥv־v?#Yb%j:d@2fDSz\s5a„ ;N~_{m, ꪫ.±{ofmԩSCϞ=C߾}<8o~p]wF;|駙v Z’ [Dfpھ<`XC9O>a}mIc`饗ݺu-ZST;uY xf9u@)uX׻&!SV%>1n}?i4BPF0,HT0JZ*L?Ϛ,`,aĉN<[n% 9sfHσ4asOKo?a4BJfj۔V r;YW͏q6..&oQF1320dV+\%p1JCըs;q 򶭼k믏FyomK/_:VO>>F8c2|aÆ>YUVhzpv-.LJO~bӯ_}ߍdbuy_L<o IgU>bu'On3|Mօ>^z&H0@kL>g o w }mehm9Xut_t/bos>R$9@0(STlb2riq'x"O;lJe l!a> | EC=4LoV.|B+|DS[8ࡇ_ Ǜ Sf(JR^׿5YrJ4ֶ"BOtPXc0tа;7<,ɾ_>oB*_RobGxV׿lGJ/`-]&-톟D]_[:9[ Ƞ.IJ] 8πM:f?cgcI&"SX,m~M/b<Lj#w.xiO<gꫯ>7hq++gDzSV /04|n4hPt9χiʵ^#ve lѱSTi{oqrjQG"wWD/ `{>pwƭrdۍUs9',BO`+VT2uoi(a1\z7ex٥MhG̝_gpZO6]J\*-° =yrE^e _V-vZגROyz>f̘X~b ~;w}+Z[o%GmB|U?|{wdkmnkFN8_xNi_Yc[{j[0,m?$[׿φa1"+-lQIhy Te<)ws+"k`mu΀_3 tPt&*965Cd,zyoSiM74JapRۡ^F7V[mw1~ʷal;FۆV O;(|٦Ƥڼ#?1WFxLJ-pOcxcжsa,3B(y晅2kc퇡cªV˫(zc/>kuZg${gh"2bU~2;_ZuUøqb4A*XV|i˶a)a[)V8"6qSwۦştIaw(VF yx 4!'AޖXTxC/>l!+U_N"ػ=iTb^HeܞSJ-(7xCZx P½7B09f9@-0H-BQ5g>ńHRK-6d~#"l ߃/[š;97xc|{3(o,s n5Ru`5 Ywufu/n駟)3f̈+\rb w)WzZ,y}R:'\,c6$+ 4}'WEP]c+۶gL4)F}Ôqa w?O_+CnQ \JD/ߤ-⨉j՜jul(ʘavd;K}2J+adKoҊ8gpJ2+"%Zd/Y,^6E#;ۓ 2ٻJiZ)Vj2LLsg_':KIJ"//<G5.v9_W 85ŀTsxecO xe~_ó/(cR‹[lE9xP ~M!m1Y¼aJ˨Q# m5y\0Ch\/i!(`5.c]2D6նwSuylc\OOZׂ! 8@hѬ٪3@իWS*>Š >ggh` mj >'y$+lk'gP*\)Jb.s/ghx" 8΀3 ] pV,V]ghWiWd΀3 t OOXt+Jb-Wͥ*ghĀ"(gp<O :eOoO\ uc Kvg2`(n}}0l6+k,: ~KwppCbgpꚁT|o߾ӆ^ 8΀31 !1Yzd U`J)|~m΀3 8Ā"D SXˍ뤗ܥ]m4!]vi8[΀3 T̀"S%Hr].v mv :Eec@}I$gp0HR<,?+D{(WZ:f0ٴ~ xwV$Yll{hg !RM6뿬tB pu~;(5};ۖu/_E[X`[VprpC:_7<z衍xꫯG;C+Wy0!7N%!?)Xu1۸1=?/e|ϕw7{R %N*0 kAj* 8@`hYO`p'h{:\yҥxe.꿙+?\K3`텋biajnSGyd86Vxr߿гg)eԩo+/"FQLX}`spbª˴iۍXe(&z"S|~XӧubB]Sv(矇ݻyMcaV1דlj6ߴ m/H>ggje 餄N@ ů Nw]´]~O$wڿ]*>Zyےs-LjշrVdۤKflX^ Aޢ .΀3 S*[t%*(}O%/enm1`)i8oI٨o{6\l9@07vӞ&$\SXҋa嵰]kw~ wk[=q]i?ʭu+u6g 6.N`Sz1ORf۟mb}USBm<[دX1q΀3bR%Ņù)\d: 'u }kPWiJ&WNH}\_E cn!5#H73 8fn*. [P)m7yaiH&Ěatqi|T+f 6c/3 8a#69"6QO!50$UNR?,XtΫl<Ӧc]iW94BXGXU* s !jTl\S a*]5]V \s͕ѣG ><'TWO:5__z=ܹ>}x`fΜq ;o߻w ?e<U{o,)$  !dw5{qWx@֎Dֹ8/b zJ Zvp5.,L2%la-wuW5le08 ӛ8l =}5):?Oo'o8p`lӖ<=ӊ.A|%ɋOzK/ nkw/͵v[@,lmgkU=\8蠃0~vۅ/2aw_Ye矇G}4qw 2De qa7tS#8sÂpe-2PYgnc4hPx/~w=ٳta?a\q)ZYS,=k_';@!p#~P`IaZQ>^& Bi (d&6!+(~P^w=9<jNP=M5ӯ=v%uܬ6ns{(P7*/q~0!za+"*7ޜ 6Tvp+dsaM a0"ϓpn#S6r:y\s,H/h@؞: (c?ꨣ-Qi~)Y|)5ŊkWiFT1"yjdK{hX_[4ֺR 0yjbbE hO[餝|\UGLJ=q̊ж&%bcL3 ȐSԊ+1T8<_LdQ|;1A*[E+iVTp9mJW+"[GV"fN@=-D~#TKWA& wdCmհ%X"3<i/rt_~yKZYP~%)y9}X?i6b3l] dvC\ !| ӸBO4cm^+X귊9K  3ąz 6NmR8Y>(v) ݚe/"۩R9c .f4}܊+Hpe<֬뮻.hyYO y /P.[;찜Xrsu:rz?xC!O tε¶©Bo{c]K[;SE] esa-9}qOʵprzb[ȋʋzjZxʗ; [(ӖٚE{h n.@wU ә%MӅ6ׯZo28vc1}u-JAob1NomUa{gYi/!7xX>b=s>Z(Njzkl59rdL{7b'˭YۉB:*F 0,(N $cO$y0+P»ie-|G-GV&dH~^ i (͉ o\7\γS6Aa ձyG D~S,PDhNה#% 2±TPyRpS1L]-"q͒b^3D8~7 JSi#+nBS2DO/*cw#V8uVQOh~ `Ğ%p7L5D7tX>?Q`\a%ԏN\!R/-C~N݅=>K x3DèH^|k ѻK\_JNTǡ(V"p4Y8^| }Ta|X7\O;"ʂ 0OH#Kהb< PM.a0EŐ#/m*XI>%d7Hd_H\c$#@x& _ZD~iI&- "+M#8X/3;F /}ΤCdee& 7.ϟ|"; 14 hqoVOmpGn"P/HDnbF(N&f]F +}a!lrY!!C%|Du^%uR?"3cȧXA<? E 72g"LJ`rBfb+͟9`bܤzb2ə!2Lafʍ˥/3't!zńNjpXm,G1D~_߃/*SX/̊ JXR/㘛K2c{{#Cflw!k :E$~|Ur?x˃%Ȏ*C:p,%_(<PzsH!Xym͸ҎAǿ(-b~+4Re'x@6LPrw車h 9:"JT{Pyфp>/+ Y9Psw3ΝڄWe2!|&m+A!wa>.廻0Ì;xϔc_ʽtN0bXǘ2Y!?y~bi;V.!YEsݘG^6DgS߅K.1/f_.&& F76]+W^LvRh؛uύ 7[M'=FV 4'妉K'Yɠ"{Aˤ|gРA xo>|?% 7xc#?7Hn<eZ0>ք ߠխٯ(68^F .%|Aw1C?dD~Ľ )+ܗ'1=duѰ)j 'a R*o)pP-9L#xpPLTtAHL& /(<᧣QJiL޳\ѳ&qȿp<ćO"P|T"#<#%~ }B*<{,$O(Gf(zNV^Uz+3HQIx_&@2y\v[B# 7d\-zTxā+sYL\{G}{S믿~]o[!ۺrn%1hYz+ٚucwv?K.O$/,$,) V#ӄ6ߚşlmHž}FRP"(_~Oe`d_ˑТ?1+^ziL[{ *͟-mu-#"`sD!G X/R[ `ŃEeՄǘ36Wql /_@dlBzg½9@'?DZF2 ]S,hE:6'|:݊0_c}ҘRใu갽mm(lB{t>iIyyE.s8SIDAT л۸d.0D1}PaypK"|6ÂL/w9aZ} Lp"^C3i=*-;+ .o(e|c4#|#.PƏ9Cd_L9f4TAE>)V=c+ji&(vr|V5X'MdEJl"jn4D㓷cO;X!OÕ㿛9{U2i٠U/Y1qu|&dH"Χ)w0A(WyP˘p6HNHkC(Q<ޛ,/־w)v@,BؓHyhl+^"ӱWHeu=Cҧ_L&J LjlW|ʼnsL@}0`ԊM(H@YsQ^ؖy<֬<;'9v[)uJ*5ndF wSk>:eʔ>&QW[|-QDl;d#ӡOfQlXg.:sC{^:tnw.#ܹC~3ISs4K&px*pNYm\'\МY_' !OFrbCBAF%I!,p iP`|%`/!u@Y TϹw]%plJ(R~@2b}ΝI3a`e+a0YxZ Z8\Hk<(?m}:S1P?uSE-y6{-hTgTjp߁)OyOaС,sײtWjgJ2ʶܴLY&?.OPV7bDG/',*,%,+&+l& !;"~x ȌZ5D x8ʝ%L&܇PȓB3@q(PIIEv\$)B6?ejYb% v(؁MVfk u焴q i; Qxa[ J8a5;[?PIŝ&#}M2DsoZ?"Xr[L85/uP`-H_+JtZI-,HNn,s&S3'O |*& h"Q4A/Z'VA1Ađ Γ1sL tWuz=,G`N:ڂFdLоny]Oж2.fJajfLO׌i6f<3y}q}kPt_oƶk*3׌A& (׵.K‹,arM pYKXHxL"pxFHN ?Z*RJ)ho P*6\OUaSCEin ΀3 ˀ"2R%N\V3]cs6۴sekjK[&6-3 8Ug_V:u]`pLT6Y l'cOzb࣏>ˡ.SP>`y mhcۘ67 ڒZf6 GnKN8΀3Ј7DQ%NDF;z+tCh7ݹL .̀QO8Y4mehwƶ ΀3 4d |x1NLOOߛ5kh s }#onuh;YmK{t3S|BK`vG̵k^Ξ={׌~?n6~_m*9So1mƷtSA^gp@-"rк<Љ.&TYaBql*?yHAaqLYe@YLQAi(4\esqh$3;?n>#f!"2:Xvh+k74aڕq>M ok\^gpچ7Duvl\ZEL 6i11i2apv,3DA XЎOڎ(*f\+O^N8f^mabr 5C.کئi_po} ~b8΀3::i]6f ǐNF+L`Ld'36Byɇe Sj ж֖֖֞'@4X'.k7QkWڙ1K?0#ڗEt ֦֮S6 B34G?΀3 &g9lRII ?.OEM!a߄x&2&<q XA[‚rbJ ~p ~;LgܴocvO a<۸<"RO;ѾvmYܳ-sgpZǀ"+m.. Gj|fFyЀ)4VBUvf mW ?abah[kg\;'俵Ȁm|@c\Όgڝq!1 ظi/\VvO^M{Xq xs 8@pCuu| \3).LnHj&<Sj̯(b EÐ*#-J ) lJ e2UcaC$ڕv'lƅj˸<6 t<mv|ئ6Ix'F! 8@U`qqJ1cJ~&'&& ̄<!Lr^ E"o|.ˀ)ֶ־),’*+1wNk}hwdۃi\XAYqlv0WQ.@ڮ%e\hK3cqr|s 8@pCu#mebB5e&')[7H~*- t^sQHLAI0qo YY(cڌd|26qM,qg*p ~6 XR !xe|[+O 8@UpC*4u!L>H:1i0i!(&0O1e\E`fSD΄ӧHǵ2m'R X1NiC\ژ`3uh_åm<إMm<ȟ .΀3P=^! a0GPT)a.@ڦSRLq!lJea\jk'\ڐ}/*k"FD-kBXsB 8@pCJDq1L@&60Q1q1bi)6ё83B-<9%Υc5%vQFgnrp/K3@[1qM$L[[8vM3ȟBA`ڍ7đc͵r 8@u`pqc U2o O@m[~@0}Xה ܬS`,l.XAإH"c6vmcxXzj̭+:51i.WYnjYؘ2p]g 6T0/0%#uM95C! NhN>1 J)(!͠Hd[ץLM4?a3F,-u9c-g m\3qoeٱĻ8΀3j|h5]knꇜ1i~aE*ZZ_8\jcƴsbnߥ(fDdǺqc;Wk*F΀3)S6[UK/T܎eMI1J"qsb30`㗺i6):õv:u%ۖN|z,agpƀM6U+  laO’%ҳ8LHkUF,OOl8-Rk4l~\8s6q&nq&Mp3 8f'VSإ cak6Yp6+(_Wk)/TyV{ cR[[{W5ra TB:?* IJ^HM3pMW+, 7[gpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgwB،##IENDB`atom-0.4.0/assets/store.png010066400017500001750000000451451373702275600140670ustar0000000000000000PNG  IHDR@>sRGB pHYs (iTXtXML:com.adobe.xmp 5 2 1 2@IDATx$Es\,Q2%#A>E\>%%HvY IK9s=Nߝt=yީUoթ>]]3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8΀3 8@.rR"myK^3zk:@Do bn^Kqa1MK .-g;4s_[3PvOf|mI&Ʀ:J5,YzKK1`z-OÝ:рc`68;Zg*aʲ_N$J|V8ޥu Ԛt3g@xRAF }hok¸y]i\t8nr"3`rj`Rq.6qdR{ X< t%lrX`q`A6FR}N 4DɹLً\)9M6Adҙ _H3q#v#[!gchDӉ2{pP'0`&K0mvl+ ƌk[ץ3@OQn#Ə6~ `Dy%@(Kg~Ȥĵ Ҍs9*Tbh>y]9nM\y]3 VB( 'kץ3@_c1;BƃAĹt6fæצ'}l.tv?,e+&K< "Kgq$ [۸PTulpOcЯ207f<෱h;6qӉ?JZYΥM X 6Fu X"/0o.m06LdzeMd4[AR bb(ok> gqF=zt/ꫯ_jMT=O,裏Ou!W_}5p 56,|{߫_.4C[Œ`ͯEg`|f!5\=gӸix s=Zhk-"4L z{׆nf׿78,?AtMW_ . s=2KXb%0|uɟ`.;餓Gjlr03ݶA#珻'3n3"*:@sѧ+niB"~꣍% u_RVʿ+_OERu&ÉrVff mUumtu;]tʻVJBާk!b²wÄ5qVfiJN:i /r!%%Zr'V1ӖbJx=:/,m喕tK2g>hV̟'’B=00nc3\1 lV?#;^{UVW:x;]v%=a 6UE=^a%ȟxZI({;MzYmuHz4ep^/3:޲~s !\|a6 |I\9on6UwG/y_2r bg} 3oɺNٟyя~Wr+HJf+BO\FHVSENq-ayauaCdwcƌ) 44쳗>㪛MBKK1믿.{ZK;A0nܸ[o.y"4Y_.]N.~&*,#,* wN!pKTB+@C=TũG,m,?Ǥ]yK]vYIAJcm}5 n;d7D> Rg'׬֙^s{k  MkHbsp =f4=+k  C Vn##vuט&㬒kƸbnѣbgw/zI7s1_WNQ# ]=`mF\0$jIO=MM.|AڣsmF>à&lNnky'L7t;i>lt[ Yje#EK=oP<MR5ĽÒK.x0XuUސw9&lH" / V8%`sk`"c&ӟ4r-1?y^;aСau 6[:F%O=ZZxE8V1>>o͏NnXu>"/zq+B8+C޻ 'DOcu{gbU% >:|ߎQje+{~߆W\1܎鵹ԁ`cJ;t oؤhJ`.a駟X{k) .lR/Dw^dۆZ+,>.i.#*.fW_}uxdK$F~&>&C9'R^U$Ѻt!yhYU2-;,JAwq~0묳v-2IgyfC2BJM4~tw7_SOE&f. lM`|f9)WGle!Cbk<6ꪫB8MnSq'@ʽP`:K4*? 537Hy#)0Vs!!7 yaeEeÇԶqܖ<8 -BRJ: M_*aRq]w]eOq /pMzN2J飑C9$ƳA?:JCG6hꮯQk2,pGkT4T*DO4Gl(B<e3-r3^TYyfaÆU Zد2v*y; dLjQLǐ}i뭷y iըĆח^zɢߪ!pm,NG`.'0ȮvJXkcpt"瑡KtU%٪2ZJо4 0G{챥wܱ$<–]᭳:UcCs8s9w<E s <cG`" ގZpW6.L=#SI毨b,}]!`\#S;o4)/K`+wlnvgpE (j0RpLI'3FZij)G[}yDzu)McJcS3lVzYV3TGEˏaKZ3-L>-sc\B00v+( lQhE#@cGO&<3dqK6o Fc'06Nџ?+3{N0xXFVhzwB|5 &VEyɍV{ȋ#"_V00nĆz;q *XJFѣwti;tnW'BzG`I/q y'4k˓k?\~~^%Yttw64= }_*/]^\UμCUת^Vb{䦏%R5{S]R@,K\ m .@fArx@(h鮪gQm^|K>4%SdFe5# 3h6a6wx[ISxi&.=)i)NLze/_.4ѓLm3.s!;~Fx~/'/qK3bNSb)S ^tWa;L?\1LKra (wei__ɾN4}gRDԭe - \ D* za /,gƩ8.=@U۰R 1 ti1q$%"gI?ȿX!ؤd74&";f3L[|3;^ٟ%{F;M>[v弪ٶB@z m1dalapqN*UAi굏0aÒ<V:/=R橞W zپe?ܵ\慃:(o~,o- 1 ` ˊ4JΑa*$tÇ|ѻSWu kv܇шܞOh&cmfwGO#_.9D(enEXY&h*;xK7b3-y'Otf g6VZZ.ogㅲt5ʹNcfi]++ Lkt!t0f4zk+Z\W}[ݽ/a"b`tItǝW  Ɂo}.P8mak@g41].`P_.֡/o'uX{``bE+A+P[L3~}ǿlcpNg}VE{q΀3a8gpgpn :΀3 8 pgpn .;΀3 8΀@>gpg`1Ѐh0fɊřKz3 8΀3k:J/r׍ w^F Z  dt,Sz1 4V@q m'Dq%_ҾIt3 9ZL@h+4yì` ?0Z?0Z>Nk}+1 . baHI]'*Kk"h t\Vp-n`03 S(bc>f|0x0 *qG$tMWm4>T}'D_o}Q k~}駁e裩yńcF ePWĺP'}7^#O pΕ'b7,1||}N$!!NvsUOo?DJu@+$U>j.VV.CQ y \ ]qE<AG.x" K%rl^Fԗ1LYߴ8bVj|i&~0N!tv/ꋣcs6k8~ u}_p \&#ןPo^32I,3Z#WgЛeV7l5OO:.#<8x_c5t5\>hla뭷ҢN;-\ /~V]u.y~_~:}aW{f-r)!2f̘pǯ/R#*wN8hma]w碋. _|qc=nan¶ntM﮷zWVt\dӲ k:p:mzM-,//._~907Kkqcc<3l68vRًqOhfͮ(ͥ0s=/ٳZcw)ÝX D b',Q ӓ ӬĪ.s9a7Fvi'up!nt 9 K+jdCvGV@f VQ]a*\jʴm ظ۸ɀ~cn!2M3x1!2\:V@v!˺6qZC և-6ӟ.oc0:oay]0`H+෉%0e4sCWr楓Y=C}sHBƅ 6Nuqb36i . !{!SK.{Ywch`me;f&>S^/~gѣGs]_?jus=7<5bQ7jɰaJrER9IZhwb0L3ֽ"Z.ntkxHy]E@ \ /9pYfz}eO?}tلhNWʵSWW+ۼh%/ԥDM{A֓Ǻ&Т|lߏb` 3t& &3 w-3քQյH8+M34%}W0[n:c{Eth]lb1gwlk C9Y{ oo>Zp3g}KwiHM+ҰrYg+<.mlA]'w~xSLO"ӟo~_MzY[wuða޽.>q`(a@C{ęcMq"հ{/8lf=GqD8on^ٺyW A6-wQ@hdJ@IҚdi>Kk /K.$>qvZ*Gb[ne8SÇ~ӧn0dՔ ov裏+ZkݏMlMHu>blYx+5z sbOǷTgOt!9bȌ39 ;~FGAr{EuH]{ 5]&B:f"Xe§ :'vdeo.ܔ\SM~1=P$Y1rnFј׿'H >13۲E^ 3O4\.bUykϷ1~(HuU&[kI7^7 vaK]or6wVeРAqK/4kk"u-nlc,=3qisr,QEKZfu N1or h63\t|O}b,a٭UVY%F?E{EuH]YhYƁFW= K H.FoQB#'*}uSSډtVC&0vNL֒aa0Vyv6%OO1cLxU&F\g g<,a %,/l{;Ge\pAժ_eqM͗y[orً_}CjwO=@^lWs7?k0Po1wBIf^]-Z& U%G`B噧ȏ2B@k0H@ޓ1&pJKwSU`u} b>7~8%>0XAX%'( V>M)FjdAa=ZSk#n dO.L)Ѐth W~OJ#GlJ"0Od*Y/+0iTґGYzw)}7+/K{7 ^_.]*ЄGyN(;w7L,i iwDf )ʥ@PpQ`"QC_ >D Vt9+y1}VJG{Eth]ۤ@jfJsPanz0ʠO$d 6_){&B0V0ZV#˸U.ZȓI:2L=UN8h yM('WM?\n=r2q:I5O``a'2p +P90iTꩃkeҩ~Hd6}!z!Z$nȝBĘ>"$i/OI+9׊䑚(}߭*zxUEKsO&SԮu7DBtzR'@?p7Owէx]'F)WTWԥ HtLq@K* 4}'*tV7n>%\%~o9- V~9ʿC /&YzWU$F p@s @} ?(w7'3 }-z@YʽQ03O_XJ(Nd|aU1زsUirs$^,Cv\96,DZ*4JITzO+6vؒJ|BoZ魱U[o5Ko%mzOP SGSM5UI*U駥Ccd@Ŵ;,9gVN;*%{f7e-Vfx^ϝ` tUE ܉N!L#w/ -wL5}cVًzoU aQ7/NKG[DW^EblۦG`g%<᎓ O*5q7M?5RKׅ|%qF pauR^H?Jت:QRGEnX3j;b2 5< lÒU3CY\'3b<)l&^'M68_]ir믿^Jb~6HIo.ihH_.4Pg)g/kӱ^ojmQIҬ[o"z]TW^ERip=m2Γ;JNi(x$@eoM]<-' ΕDBw5;D8NxC,($YG:2Nq \R>Dz m[d,|,!%޽3lذ& Vyc+7v<>0rL:1V6 6[iu֩/%}:EK5! pߗ5DiV)˥UFtoٺWDW֥&ydqwR)~d*Ǫ ߄ U{[jɑJ8FFO6*VxםX J¯G0Нd coq[s{C &f 砣i2ˣ2:^Љ嫯 24yx3{G}4n-n\|Sή[P7w؈]K/ZZlD6?=^G,hPO>/<_ &0b9H@z0 j3 >\w]w4ݽQgm"uiT5jTiHqnmt|b{+RYB'4V{EuH]BG@'!."rN`ZvO;ZxEl03~(cZ[E1 r/+[0 ::`'kKU`d e /HXf!ŨdQc0wm.ѣGԲ_E΀3bXQb rpa˳#(zss6[U\pk r?F{67 { B1vF ԁ'&o]By X?."uxL)w `a)ad:MzqK/ȇa`fo{e΀3`udXrŐUXA> ?HX_qun kNpry$* ""ޥwynQx'a|& /ˌO]L#7'^K@];=E~`20tYݸSrqg BXIXQj F i<~Y͗̄W=,rYZXTX\$<#<-ԻszR9KP23TgV[ꑽ dFE, ,)оJ:l08_&J:XXñ {}ogk 8}TXYSLn&FȲ1xe+H^뮠"iX.@K`ùޱ 8΀3 7Fpgp@'@lr x~ iz0;~6ڸȦ): g)1տH/sk5jS+FvC x:V@6 {iFMV&X; `X;K J910' ϭzꩧ' \uUa_B%[榭dL->3鶅Ve68 v &F%SMe}B!7.L?5_𢽠s`#裠}lwF-eX>m[YҷH>M`2V˼2R{0pq:V@\.6Q޳;=,|r7O2z&+8묳xI$3zRY9r7x0*|wͼ??|^.Ef뭷~k-WdH&1bĂᆵ etACUA2l}/9U~>L}\SN9eL֗_~LxiWЇR?=C^Iσ_̙{ގ;6T!*VXiw~CRz+jς2pTIK|:ش }Pq q3?HF'tn6Ŭrt\ L2s=^2J/B~F+ q^z`XxB o/m~È0gƂ \j36؋l*[0Y@O-7qo QeG|yQxIHz[$Sv!7 yXBI\ĩ?+V F-C1H('-C ɋxf!B7t2( ^L,K^HS3n01xM?vc\:?tьo:^ M.lSHt:n0Ggt=ontx@^q56JQ.@`iGje*bFML#MYeTtM'&O^7y)/f;Oא@Lx6Ab}K~3p(KcG1aMtqkxxt[ RK>MFSoGO6N t0ҁo]XvAdNEB5~l$ojp5"O^7yUz)ZW2M\G$ͯJ9.̀iA_1nl|s cVL)mSE~:5_Vxtkiס.@hm 2.6AҔL)ONQzROlid >&Hu d}I?f 0k♇L9_^62`})nVF4;\+66O L`ĆE&K&Iآ0TdWRE8.a0{IDAT+⛑'{Ε=O6O6WOyStkSZ}i}J?_&KӗPV ]i-:3^t! fn0&A^3`zm}kJ_mOOZ۔3^pZ%6qQ &8I? FJ\l<@Mp"O![llջ|E䝫2&+ ͨᓺѷ$i) gĹtU'괭p=cyȌtZ\@"M[t<5LSrPg= ~`ʀ`Ʉ<6#7qZިHz 1 V@6Q&4\.fߔǖљ\𱉒cPNOhէz"Ȃ~c$:Go;5!l75䱕 ?p .@ k) a;L( ".M;Vg3|UKOSg&?8-/l|XyrP#C̏>DŽMfD>CxE[Nt=?Sc8\~;Vx 3&] )$ld4c&I ۱鄙q-OzXUN#)H9fҨ a\q[,-lJAK2@2^Ot~FO{͘ <;q,a\*ʥ :¦Ӹ `4q䵲U3>xZ- Lv( b"Jx\6Y2w69f esi!df}kDIm'[V b.}/FA譭r4=6VT:?3Z?譹)ߤOa\g#H'VT(k-B~ɛ!)1GzhT꒦sμ6y'VV&?$fKGK1زel7)]q8[UJ]zh:I-̏5ㇼ)\ʀM^Dބi imtJO81`6975p𓆋i1>ANMOS4Qi|zlw7\&?zMIN" v6`f0!"G->~Аtb8 34.π nTՠ4OOkm>OKHu76tZg78G\g kou3MIqvmf~sӉ光7HY\KN%N:H8o: KqN@h$c6 ,kKwꩅͥ V{K7u@:2Iʆp_6TgSƥ~KwsHu8[-\w(|85)}q4ݥ&zUgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgpgp:@j4-IENDB`atom-0.4.0/assets/swap.png010066400017500001750000000612141373702275600137000ustar0000000000000000PNG  IHDR'$AsRGB pHYs (iTXtXML:com.adobe.xmp 5 2 1 2@IDATxdEﲰ,K˂%A (*JE$P ( F0|*"Is^v y;ݳ9]֭zԩ\(@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @9iNMOut *]P(F ME. @ CmFZ~5;z~e$u6BQBS3ezHg `=Sα&w \rqX+emߜMC&O];A^%MJݜCL<'9zy0tr~rCiY?1U*U<3f̘c&?Ür\r]bfws#18)WLvf#P$͔ew=2CXIw(\~ "6 _֬{ҵi{=3GϳfY޹:z:??sRNZ&]EaR$7J^)d;5I"ޠԮ ûhTa.`G\얡F nK98lXOY/anM\l>\YGY=}(FuI7*F7*>FCq #^E}⿈sZD,(~JAqNqxN[įsSe8 N<yx31&TǙGߋ?/~qNoy?+i[9o:=r2%|'<'ϟ-6~*?Og8SĿ/$~Z~8]`d"/H@1e?uķ.B^ λKK]~&s9K.$L|?݉@̯^}UCNrz2i9 L7]I.id%s̱x&l/݂n{>}r*uRw\"Kƨ?ExN;mq=?nܸWO>lV @裏ε뮻n=y^x។ތjY3f̘sz.ޛG)9%{7d8k"qǯ|%{[:;qEǎ[9{2QU di^)@ | K=ۙ@`P5\Ryp?d%˚MT6H m '(nd CƐAˡu L2'',1n<=c3i?LmvƏvniԅ\B@W߮?-F\lM<c3߇Q)L+q+xdr(kP#`~Ȍe; ȕ'Nr݄ r>,OȏurĠ|;W ߞS Fw9w V ;P@Yr f n1!d ACFz 2[q/:'d ~fP 0(z.T@,Svdr'kkAaĤ~7v` ZxOg"1E,_aL~avEXvltl w!tY/Y^Ξzf9R/oW\qH>\@> zٰBgpB)_4@7Y,Js(Fy( υ¦Á y-cX(È!}A?^|[*^|A=,W Y7Ȗ嬗NK.b}g],{6vv[+O^o/~&yI[r~R}'?ݳM-" C+& r6,{Cm.\n>&iVy/_l.2$%'|rn6?(t[]|_,tBջ/j 2d_qCN[˙7t=[8/Zkb-(? 8+8yGFیJ 2àl3M7ݴn튍7xؠFO׿. dzyߋRK-U?z~o[3.lַx;Q1Ac";X7Gl(N˟urC[Ƣx{[\}eY&ww/>~x-K! %먗~HY' F@4eoBkBshkEh|m;=L:UIXYeU@^[%Xrj7" izfgGCM2ADquץ8x<|mZ?_jj3D~V?ZaBv#/#ㄵ/(jt,$F%L/ 8xY!f-+fdnZuA]5ch) +'{E7iRy'+R5qqH&50 zW#X}W[$Au͎_#ٳrfo ^]q* CgTWQ羢}E i@5~I>ʳ $f˄<=5 7Pկ~US;]RB#G3FA5Cz&@ސyUݮ\r~W$FaY9a(OmKM4'\LmR}ݗ5MOzSO=nb53U2iiS^ Z,"?k`JCrVyvmMaies饗ynNqn8Tz}}ݬ%޼(3;2쩖 )4ӕrvBZ˽ڛG>2e9\Y3VQ*յ[X{ 5l|I>|tPgU.'u?xwI8,!\wdjfvN󂕐7Mi6<W_.{M23X+"*r[fFzt@UX uf*sE$}߈ L\.lǴ/En3_bgfđf,8ln4 ^{mdMzNpr]@ dL8 y{eh32fpqXu]Gyg?n8c}{)M@bvY%P~#HZ~_p'?tI?ghnr-iBb;~B{'SBۙ MƤK?ϋO?=w_@?+Bկ~6mZzc-;9cqjiV_ OX2bln9ZU+N^)zC3d`rbaa.' 0;x91F닩;ߩvdPYwye R_S;fVMVOjH*Tjyfƴ"ekGvg+'Ho$^K352NG7(QGu+Uf#UYr%\mI y+kO9Dk0[ /f8y^t=IdBtVIHq֚3Pâ[R|5UifSwa4O)>y+yі*&Tܔ3򧇋rª4uśw32l˕tdnv5IMnrBUtX̾:)q"+q~Pg@dI"p%?>VN}Jy5Ĭ.%WurbP> )Gb WX%+tH<+ăXkq4YhP]Y%gYI}7J*~ɫ>'~81Vyw[n%i1Tz}%|rbddIb/[Oi1ÈdH\'9B7ߴ;VNߤmOs(} N6P'{ |6׭4*CZƶ/[π%ŭsGKBB}80D?O4ޚIaLu<jXem( N$l(dٛ68apAg-xGnI&az:z ||k@; ly }H 5kGhf5C'LZJaey-+18q'.xc1'NvFyhf,fS8[YO58Yҙ7 5<X:JP9 ΡT;',o-F7xA Ntۛ-Dmޓ u{y/ ݪV:Iz2iU&Ϸy&9Y[H 8}!= nI' ,R0S"-eG?=gшvFSrĤM&vZ>8aRSoC*zsR`hIã`XP^{~:"Z)8`C\APeəC&gk~JS2gkΙ8zGW_~fKU}\\K' oi{ uR5G-f ի+(0V$Wjy5g0ROxlY@6/hkު"Iެ_`: d^)4{rijS#3єm9N7qm [au& n3}g@WIy% _c靬o$#_B rb}Nm]a-7|8`ViS? jM$%@}^rx;&bvr'  3 LJSiΦ;z#ޱ̇'+!)^{ɟ&8"3+lg̰M3U^*F ׿1Fiv˂"g3g7alrUb5y϶2.s%43.FZbfR4#+!(N84K+% 0(+#FeՇR=ɳ|e53 JTp+) K3;Nf4EKeΟS;W[C3/zOT h:,QU b3dg)~[gKRV9t \ .m"pH:ϊ ++WdJ*w-oyK:HN}u,rU]";Bh\O iu2΃X6tڂrp]&*mQ7p2+%&~.A6:AKK88PGrX2)6ofq[Dc28ޓmdסĖ@V. W'hfW̚aVSj )M#1I<[SlWϭGP: |͘[mtjڎFco48O'$cnoc0@q㑇5#l39M3}=W|21#?:")`)Ot0˄~wކC7߃13!k|_m厩&)nkb_Lp3tzC\&V%:A=`oYH_2v3pJmk|e]ܼ1.0Ǩla}md[g[]PN.O9moV4NN 8gd 1??E@`84IÑP4P2ʟg?={dJÌnC,j!֝55~M21=:uMG4q!%Вz ;DC,y睗:5D$ @ˬ&t*{Q: 4}ś#~H<*噦tRc&L82NKW6&J7ǥ{W7+2# |4;я6HGǰZS 282A3q`T~ބ48Og+qsH7aK}\ls|F,/—^zi>ɏ9hOWj %")NǓ0.cI|'<e bKvYUGzȄ߀8rĊ\FCR Y:Z^xCVⷉ߭JX<]٪Zqf}V95 Ca긦4|Q@iOq; ~ܸS&-0Ug1rûH9q;x/!‡ .N9+顱ŌbV ^'mW s_$VEZ]uj3P?B5I B ca?ap3'c*oG5`vdֻϐYR<7 Q;fI ӻzzLf!/Gxxݴ-;bӖgNȏ:ጣoW79T'.'][pګOSI5+fӭsN۽ڌ2v1*fbt e ƩO[6MU|e4:)?+EfX>;|TZUz5 npښ lRg\+=n?n_}&}aL lGnLAX#jqUR1S~KϹR$J/ZO=&g7wb(;;qdPDE`VC7ƖM視9;N`zpBGP3LI6t;j`4Yί{՞4XGHv Wl64f`Az/}؛js'VҠi;M/Hl'Аk8N@0dقI՜\Qp NW.s9P*NPNJQ J ycPw@sٝӁzK_:1u6bJ.Ѫ_zFgRǚ0{H+jgG>8%LH09V&gD!kt^.=K{R Z>_t5\3=j 0~oAqLx`2m/Iy9Q'\ufG 38yMyxo1eerߩ?j{_D j*@5o+\S̤'Lpixxԓ+ب/} w $FP9, Vw ~'0f䜼%v&iz3|3+ä1#\njv|̑⣛NCYtuf.ޡiƔAW. mIsϚt' hcMp vp¬9uXiV!0;@uăsXR}Ȍ,dQ[d|V5F ɟUbnUY^ m?dhC DF1I>#]w]EeG˫gtr1aGB~&]]Z ک} N53E;',}՚Qe1CɈ-^l1`afr5;2Y=r'iFpZU!s׌Q:ȹ5cُƧ /f=9~ԖeiXī&ٯYWY}֪Ia7[GW7#g%n/(=IihE:˷4װ} l? nLOT2 e%M%d,4Oߙ:uvMk2hL*KgRu.7-h<GFM:Grt b.@6bʻJq죒z[]/Jo8Q*-^TQTU& ]sՃIuO0 ~e40 n>5;:v/5;~ !}0eVF?5__(qoiLjy:l;I5mDt@#L#u&V*]fF;.lL溏iIh[q#=/bEt&#@ j;чpr7@ PF۶XYPé{[,X]v?_[kD@ 'Ábt 4| f"^&pi@!4X`#8 %d3s-|P \vel]^]ۺ埈|MBN$pNo W0|ZTH6vmYa{"Iҁ|};h)Z\J/<@|uK_e18iLxP: k1Q|#h @mhӶɘ.SAfLB=zd'r@ @J  }ǏcnMx('M5l+|I[e*2@  {)H еdho% ֳ;)D \(xm0BDel@`(dem(Ƴ݉٥^ʁ@#hI|;(D#`+m"ov–]sXp"`Y9iGZL]5瘣ݹ f!dܝ"4]o6~[ "n`ӈF@ z /8?9 dʲWuT N HŸ?+W2+da.ؑD❝eͦTg6J ,3wߧHl[N08r-!^X+]< 8`AG@[#Lu宭31܆C-R hA`0e4o,7Zn|`UW]m3e/.P>B]ˆS{} +0 =" /C^OR>q\&s8e"܇]e"2AܟÿL`[,W|C`-Rۼ,;\~@,p .+G{Wq7?+Zk8OP{r-W(O?tK?O{ _#H\mQqgԤ//J{'zѕ_<pꩧ묳NM:|U2=Ŕ)S /XxamV~?XaRo[}?~_Oavi?Ї>TG?ǟ'W*Z^I閒grYBCIYeUf7z+:rvb饗!a{ٵ$y)M:sjU] V|pO\κdYbS~ #<,0kĀ0's1x≽{ pYgo}QB=WdS騄RA]z f%Mtz $N:u=#kP 004(}{Itb;+L('Yg&L'G?"#n#Q@P ZhO<X=q>Ne~Vͣ1F'Q  +Xȝe;DxP <衜 auxf,C}G'kJ~v~`4 B\pav7'T2˛,aPw#`Y@/y &/bqiW\qE1cƌbM7-nb7VG\~'7|xm)vijx?(nʖ/~\sUn7e ӄ2a@=9gޕ,"?xww}޻\usl}=ɕW^m݊8x~o[3.lw>7Qx0^P0&!u B[\Ndo+YBjDqwՍc9rb}2eJq%mY\pAISO-K*4t̙{'((??]|ӧ~Li\m0Q( Z bf'Y9*fd]1#Z&LnT0;m|(-WOr1f'B+'ieū-һmrr]wUŠ +9?M ,$HU(ђW^I/R5CI׋_YGMy?qX]$Kl$^Kʉg&Y9GI t1o*|d=o&q[ D7I7J =eX,zs5>:[lQgaGĊI8~ɼ꫓Y/w7.)pF&$֨&;sK m]BQ(|\>}К DIDATk ˩О;eUJ^@ GL 7(,C3maV[㋵Z+d0b+P'X`.tV%6-4W^yeL6#Po2_VCk uz2kyCVFAr>^M묳Nqkvܳj-L9蠃~:m! LlDG5"YqAN~ŁwBgN;9s=Ƚ AE<ⳟl8#I#"o0ʧ AJE %CH1' t\[lX[a,#'Y6l /\7G -jN:>h2O9唴im7H7ۼ/j]֊+XuUSxJ@?ZLP{p>=Pz93Zf*]0zr=)~V\qBۦ VN8+O~4$Kf)֍ƪ̱w&sy)`w/X}a;u G6ןn+uei6`ReME2ma}!Xf٤ii;m{a䯽dkWG!bJ?Mih{pq嗧C%ͯ~Vg̰g;';0Fzm8PDA>\lC}g@ [S kf:T=*󨣎*a`\^|AnQ(^od+'wF F чzX| [cˉe3 moUf""MKpӌ,Ɣ@l殻r,ZmՊ 6 ݨL&α4;>"u[<<[eU 1@Vԁ,.CW&~m9(&sAMCorwnoZ#&rC5D.(~ϧ?Iwp᭷Zpg0]{x-/$(Cd9mr7ļUBF dp!m))#}g y}}F{+66p4@aeO͎oz``aQ@yGA#-D&Y[UMK/t6ۤp}_| tM 'PݞZ/&hb+_Jp6/N[^v.VR8rUWU{MqKH꽫Z&k6#n}-Pe nނ2=\veA *8q~U2fcf8z,(ԋ~@ ZXwGَK/:uj:ϙзo9}pQzVIԍ%!u*Wsb-Uj>0kٖCgGQfⷈ3- G [%O[hͪˉ%n/"Idbdh'q~&j堢ՑlT}ݗ  @@@R{*^WS<ӭɏ4ʤC)Lۻ73>e9)ߺ&;|mڴi)?Ԅ##x$~x- eĬ5AGM+7庉kY10n)ASmƁ&꫶oMɍ E*m#[ouXV;kKdW\Q F,'tRJg}1mAkOcţYm?ްG@3S5&&7jU2왷n;npB5ipׯ@iESèU+U"S,MbPXU'uҼ8)._N +4 Z5f?B}TtsX<|)'^;9PՑTuAG+N%:0} N+7]Q L0!駟^7&q}W74cpU|p5+'+_v}!@KJ\1۽^X7 u _2kWtSOU'?FU,ԍ8)Uw -ŒӴ}myUiAu>0,hxH;S NoP'nW@uG#҄Dz/K zªI|\px}Ybp_qƹ;XF$D!xy; $dG W=Bl _O1Tx.VE H>a݄>b"d4Iv}}gԩSJ$>>ikn*Mn\W҇P,gl7⽕/K/Kح^vH֠.B(M$N;z tyO~Gۖ,r op"sx3+o43J[띩>}>N;a6hۅZ1PjF>Z@U밎70jUlÞVXK͌2p|@`hnjfɸ-ɘh(OyP ЉĠ(S @ t4#58cGU.P @ IO 0 ׿.n!H"@ @䢋.B[ CS8C9,K'@ @7!v{~ (k-[5=pMP @ @#0R:[E}]U,c65ˑAYɯ`>Vry=kɷ儷nٚ[:zWno*2 9u5?=b]vN![V;iE \lv]_\@4F]^4,s|6e#=8qnn|הF]3UꪒGa@ :aP(C oFbpR[*];Z,oѰ9Na`҈gf `"듷zpp/un -@or!4ScO 00,_>}`)EnD gF)h^-OI潱NʭYp?@_ p-SXٯt"R"`Y Z@Êa'Ųi:+4U.[ȚyЉyv q] _^{ۦh{N堃6l+2端:R1}GyO>\s=kGqӦM1N:餥wO<'*}o1=fe}㏿c/~1bM7}fSO]TiM斱=<>s5WCyp֚yg*2? &ܷ"ISN9eə3gQ˟Fp,_~;oQ][/~DC X`̘1ś's'q//M }7<y8cy'7 38<\_0yWIj뮻n駟8ԩS_:g??}!Wexfy]GQUO=\2c=6hcK@gƌc%;/+Tfu\ `u(mc~G|}M Bi.Eĝoϟ=eoVhE3q='R\屶zqVNJ=yg9?ŏs-4׈k0r?ɏ素UlOlC ~/n.ܤb {Qro(F7I rD˺~:[OQwSSlrp'w!Ë;a,+*I^9~JӪPxp1\y+fA%iaT0`T.3ϑ+W NF<8^B1@&Y u\XoG<@`]fb:L|NZ}A:~u >:z}#&ǵ~"-'YBzɥr_nqzz nqO0izjE:!" a<1q8"Ş8q]\ :G2 W^+!H W^H„-# A%BaLgNW^A@˙e\|A"/D:rYqۅIÎnnݲgpds+~\Y.0-?YB/{1OȚ謼DK ]XV5v̼X?mL73<} 6( c;n G^A x3@XI{U8뱆ql_68C<aTb @6PήlL4lMy5X`Z0{ a%uAn`#~+& nnG`9ArA&[נKcM[񌟳LTPsۜ{jp  5cpPRx.<"X~\YJW8cZg.D2\W0\8^.{$ }3: /PJdntum/k73 }XFǸj 8Zddݦ(A@KvZ`ڎN^RMTBp[Aʐa1I<ʄ XXMY~ s8>S/tyY]弸\r)S!+S9yﴐ W.L3\~@ ȢyBD =p{p3 nBFsG nwówCu1AMNăntq?َ^,kP#Ly0G:0-k6V e3d`f0܎Üvvq<[NYqw &N9P&®dW],OTf Erer*~dG*J8X< =T6YGLOG#`B!mrCw̠@@Y7m:g~=(Jld~~/w;NH`n3nӹۦ B o艇.>Wz{=wDrF(J7ʺf??~Aݍ@rc$d?-C݄6Ono Q@ݣpA=Hf9=grNIswn(D[M?wz shcom-5 nK3/ @`!P֛e(+Nd k5Ցd"H5R؍P#,@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @  Uٮ6IENDB`atom-0.4.0/examples/fifo.rs010066400017500001750000000043671373702275600140330ustar0000000000000000// Copyright 2015 Colin Sherratt // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. extern crate atom; use atom::*; use std::mem; use std::sync::{atomic::Ordering, Arc, Barrier}; use std::thread; const THREADS: usize = 100; #[derive(Debug)] struct Link { next: AtomSetOnce>, } impl Drop for Link { fn drop(&mut self) { // This is done to avoid a recusive drop of the List while let Some(mut h) = self.next.atom().take(Ordering::Acquire) { self.next = mem::replace(&mut h.next, AtomSetOnce::empty()); } } } fn main() { let b = Arc::new(Barrier::new(THREADS + 1)); let head = Arc::new(Link { next: AtomSetOnce::empty(), }); for _ in 0..THREADS { let b = b.clone(); let head = head.clone(); thread::spawn(move || { let mut hptr = &*head; for _ in 0..10_000 { let mut my_awesome_node = Box::new(Link { next: AtomSetOnce::empty(), }); loop { while let Some(h) = hptr.next.get(Ordering::Acquire) { hptr = h; } my_awesome_node = match hptr.next.set_if_none(my_awesome_node, Ordering::Release) { Some(v) => v, None => break, }; } } b.wait(); }); } b.wait(); let mut hptr = &*head; let mut count = 0; while let Some(h) = hptr.next.get(Ordering::Acquire) { hptr = h; count += 1; } println!( "Using {} threads we wrote {} links at the same time!", THREADS, count ); } atom-0.4.0/examples/simple.rs010066400017500001750000000016151373702275600143720ustar0000000000000000extern crate atom; use atom::*; use std::sync::{atomic::Ordering, Arc}; use std::thread; fn main() { // Create an empty atom let shared_atom = Arc::new(Atom::empty()); // set the value 75 shared_atom.swap(Box::new(75), Ordering::AcqRel); // Spawn a bunch of thread that will try and take the value let threads: Vec> = (0..8) .map(|_| { let shared_atom = shared_atom.clone(); thread::spawn(move || { // Take the contents of the atom, only one will win the race if let Some(v) = shared_atom.take(Ordering::Acquire) { println!("I got it: {:?} :D", v); } else { println!("I did not get it :("); } }) }) .collect(); // join the threads for t in threads { t.join().unwrap(); } } atom-0.4.0/readme.md010066400017500001750000000067661373702275600125100ustar0000000000000000Atom ==== [![Build Status](https://travis-ci.org/slide-rs/atom.svg?branch=master)](https://travis-ci.org/slide-rs/atom) [![Atom](http://meritbadge.herokuapp.com/atom)](https://crates.io/crates/atom) `Atom` is a simple abstraction around Rust's `AtomicPtr`. It provides a simple, wait-free way to exchange data between threads safely. `Atom` is built around the principle that an atomic swap can be used to safely emulate Rust's ownership. ![store](assets/store.png) Using [`store`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.store) to set a shared atomic pointer is unsafe in rust (or any language) because the contents of the pointer can be overwritten at any point in time causing the contents of the pointer to be lost. This can cause your system to leak memory, and if you are expecting that memory to do something useful (like wake a sleeping thread), you are in trouble. ![load](assets/load.png) Similarly, [`load`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.store) is unsafe since there is no guarantee that that pointer will live for even a cycle after you have read it. Another thread may modify the pointer, or free it. For `load` to be safe you need to have some outside contract to preserve the correct ownership semantics. ![swap](assets/swap.png) A [`swap`](https://doc.rust-lang.org/std/sync/atomic/struct.AtomicPtr.html#method.swap) is special as it allows a reference to be exchanged without the risk of that pointer being freed, or stomped on. When a thread swaps an `AtomicPtr` the old pointer ownership is moved to the caller, and the `AtomicPtr` takes ownership of the new pointer. Using `Atom` ------------ Add atom your `Cargo.toml` ``` [dependencies] atom="*" ``` A short example: ```rust extern crate atom; use std::sync::Arc; use std::thread; use atom::*; fn main() { // Create an empty atom let shared_atom = Arc::new(Atom::empty()); // set the value 75 shared_atom.swap(Box::new(75)); // Spawn a bunch of thread that will try and take the value let threads: Vec> = (0..8).map(|_| { let shared_atom = shared_atom.clone(); thread::spawn(move || { // Take the contents of the atom, only one will win the race if let Some(v) = shared_atom.take() { println!("I got it: {:?} :D", v); } else { println!("I did not get it :("); } }) }).collect(); // join the threads for t in threads { t.join().unwrap(); } ``` The result will look something like this: ``` I did not get it :( I got it: 75 :D I did not get it :( I did not get it :( I did not get it :( I did not get it :( I did not get it :( I did not get it :( ``` Using an `Atom` has some advantages over using a raw `AtomicPtr`. First, you don't need any unsafe code in order to convert the `Box` to and from a `Box` the library handles that for you. Secondly, `Atom` implements `drop` so you won't accidentally leak a pointer when dropping your data structure. AtomSetOnce ----------- This is an additional bit of abstraction around an Atom. Recall that I said `load` was unsafe unless you have an additional restrictions. `AtomSetOnce` as the name indicates may only be set once, and then it may never be unset. We know that if the `Atom` is set the pointer will be valid for the lifetime of the `Atom`. This means we can implement `Deref` in a safe way. Take a look at the `fifo` example to see how this can be used to write a lock-free linked list. atom-0.4.0/src/lib.rs010066400017500001750000000323441373702275600126230ustar0000000000000000// Copyright 2015 Colin Sherratt // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::cell::UnsafeCell; use std::fmt::{self, Debug, Formatter}; use std::marker::PhantomData; use std::mem; use std::ops::Deref; use std::ptr; use std::sync::atomic::AtomicPtr; use std::sync::atomic::Ordering; use std::sync::Arc; /// An Atom wraps an AtomicPtr, it allows for safe mutation of an atomic /// into common Rust Types. pub struct Atom

where P: IntoRawPtr + FromRawPtr, { inner: AtomicPtr<()>, data: PhantomData>, } impl

Debug for Atom

where P: IntoRawPtr + FromRawPtr, { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { write!(f, "atom({:?})", self.inner.load(Ordering::Relaxed)) } } impl

Atom

where P: IntoRawPtr + FromRawPtr, { /// Create a empty Atom pub fn empty() -> Atom

{ Atom { inner: AtomicPtr::new(ptr::null_mut()), data: PhantomData, } } /// Create a new Atomic from Pointer P pub fn new(value: P) -> Atom

{ Atom { inner: AtomicPtr::new(value.into_raw()), data: PhantomData, } } /// Swap a new value into the Atom, This will try multiple /// times until it succeeds. The old value will be returned. pub fn swap(&self, v: P, order: Ordering) -> Option

{ let new = v.into_raw(); let old = self.inner.swap(new, order); unsafe { Self::inner_from_raw(old) } } /// Take the value of the Atom replacing it with null pointer /// Returning the contents. If the contents was a `null` pointer the /// result will be `None`. pub fn take(&self, order: Ordering) -> Option

{ let old = self.inner.swap(ptr::null_mut(), order); unsafe { Self::inner_from_raw(old) } } /// This will do a `CAS` setting the value only if it is NULL /// this will return `None` if the value was written, /// otherwise a `Some(v)` will be returned, where the value was /// the same value that you passed into this function pub fn set_if_none(&self, v: P, order: Ordering) -> Option

{ let new = v.into_raw(); let old = self.inner.compare_and_swap(ptr::null_mut(), new, order); if !old.is_null() { Some(unsafe { FromRawPtr::from_raw(new) }) } else { None } } /// Take the current content, write it into P then do a CAS to extent this /// Atom with the previous contents. This can be used to create a LIFO /// /// Returns true if this set this migrated the Atom from null. pub fn replace_and_set_next( &self, mut value: P, load_order: Ordering, cas_order: Ordering, ) -> bool where P: GetNextMut>, { let next = value.get_next() as *mut Option

; let raw = value.into_raw(); // If next was set to Some(P) we want to // assert that it was droppeds unsafe { ptr::drop_in_place(next) }; loop { let pcurrent = self.inner.load(load_order); let current = unsafe { Self::inner_from_raw(pcurrent) }; unsafe { ptr::write(next, current) }; let last = self.inner.compare_and_swap(pcurrent, raw, cas_order); if last == pcurrent { return last.is_null(); } } } /// Check to see if an atom is None /// /// This only means that the contents was None when it was measured pub fn is_none(&self, order: Ordering) -> bool { self.inner.load(order).is_null() } #[inline] fn inner_into_raw(val: Option

) -> *mut () { match val { Some(val) => val.into_raw(), None => ptr::null_mut(), } } #[inline] unsafe fn inner_from_raw(ptr: *mut ()) -> Option

{ if !ptr.is_null() { Some(FromRawPtr::from_raw(ptr)) } else { None } } } impl Atom

where P: IntoRawPtr + FromRawPtr + Deref, { /// Stores `new` in the Atom if `current` has the same raw pointer /// representation as the currently stored value. /// /// On success, the Atom's previous value is returned. On failure, `new` is /// returned together with a raw pointer to the Atom's current unchanged /// value, which is **not safe to dereference**, especially if the Atom is /// accessed from multiple threads. /// /// `compare_and_swap` also takes an `Ordering` argument which describes /// the memory ordering of this operation. pub fn compare_and_swap( &self, current: Option<&P>, new: Option

, order: Ordering, ) -> Result, (Option

, *mut P)> { let pcurrent = Self::inner_as_ptr(current); let pnew = Self::inner_into_raw(new); let pprev = self.inner.compare_and_swap(pcurrent, pnew, order); if pprev == pcurrent { Ok(unsafe { Self::inner_from_raw(pprev) }) } else { Err((unsafe { Self::inner_from_raw(pnew) }, pprev as *mut P)) } } /// Stores a value into the pointer if the current value is the same as the /// `current` value. /// /// The return value is a result indicating whether the new value was /// written and containing the previous value. On success this value is /// guaranteed to be equal to `current`. /// /// `compare_exchange` takes two `Ordering` arguments to describe the /// memory ordering of this operation. The first describes the required /// ordering if the operation succeeds while the second describes the /// required ordering when the operation fails. The failure ordering can't /// be `Release` or `AcqRel` and must be equivalent or weaker than the /// success ordering. pub fn compare_exchange( &self, current: Option<&P>, new: Option

, success: Ordering, failure: Ordering, ) -> Result, (Option

, *mut P)> { let pnew = Self::inner_into_raw(new); self.inner .compare_exchange(Self::inner_as_ptr(current), pnew, success, failure) .map(|pprev| unsafe { Self::inner_from_raw(pprev) }) .map_err(|pprev| (unsafe { Self::inner_from_raw(pnew) }, pprev as *mut P)) } /// Stores a value into the pointer if the current value is the same as the /// `current` value. /// /// Unlike `compare_exchange`, this function is allowed to spuriously fail /// even when the comparison succeeds, which can result in more efficient /// code on some platforms. The return value is a result indicating whether /// the new value was written and containing the previous value. /// /// `compare_exchange_weak` takes two `Ordering` arguments to describe the /// memory ordering of this operation. The first describes the required /// ordering if the operation succeeds while the second describes the /// required ordering when the operation fails. The failure ordering can't /// be `Release` or `AcqRel` and must be equivalent or weaker than the /// success ordering. pub fn compare_exchange_weak( &self, current: Option<&P>, new: Option

, success: Ordering, failure: Ordering, ) -> Result, (Option

, *mut P)> { let pnew = Self::inner_into_raw(new); self.inner .compare_exchange_weak(Self::inner_as_ptr(current), pnew, success, failure) .map(|pprev| unsafe { Self::inner_from_raw(pprev) }) .map_err(|pprev| (unsafe { Self::inner_from_raw(pnew) }, pprev as *mut P)) } #[inline] fn inner_as_ptr(val: Option<&P>) -> *mut () { match val { Some(val) => &**val as *const _ as *mut (), None => ptr::null_mut(), } } } impl

Drop for Atom

where P: IntoRawPtr + FromRawPtr, { fn drop(&mut self) { self.take(Ordering::Relaxed); } } unsafe impl

Send for Atom

where P: IntoRawPtr + FromRawPtr + Send, { } unsafe impl

Sync for Atom

where P: IntoRawPtr + FromRawPtr + Send, { } /// Convert from into a raw pointer pub trait IntoRawPtr { fn into_raw(self) -> *mut (); } /// Convert from a raw ptr into a pointer pub trait FromRawPtr { unsafe fn from_raw(ptr: *mut ()) -> Self; } impl IntoRawPtr for Box { #[inline] fn into_raw(self) -> *mut () { Box::into_raw(self) as *mut () } } impl FromRawPtr for Box { #[inline] unsafe fn from_raw(ptr: *mut ()) -> Box { Box::from_raw(ptr as *mut T) } } impl IntoRawPtr for Arc { #[inline] fn into_raw(self) -> *mut () { Arc::into_raw(self) as *mut T as *mut () } } impl FromRawPtr for Arc { #[inline] unsafe fn from_raw(ptr: *mut ()) -> Arc { Arc::from_raw(ptr as *const () as *const T) } } // This impl can be useful for stack-allocated and 'static values. impl<'a, T> IntoRawPtr for &'a T { #[inline] fn into_raw(self) -> *mut () { self as *const _ as *mut () } } impl<'a, T> FromRawPtr for &'a T { #[inline] unsafe fn from_raw(ptr: *mut ()) -> &'a T { &*(ptr as *mut T) } } /// Transforms lifetime of the second pointer to match the first. #[inline] unsafe fn copy_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S, ptr: &T) -> &'a T { &*(ptr as *const T) } /// Transforms lifetime of the second pointer to match the first. #[inline] #[allow(unknown_lints, mut_from_ref)] unsafe fn copy_mut_lifetime<'a, S: ?Sized, T: ?Sized + 'a>(_ptr: &'a S, ptr: &mut T) -> &'a mut T { &mut *(ptr as *mut T) } /// This is a restricted version of the Atom. It allows for only /// `set_if_none` to be called. /// /// `swap` and `take` can be used only with a mutable reference. Meaning /// that AtomSetOnce is not usable as a #[derive(Debug)] pub struct AtomSetOnce

where P: IntoRawPtr + FromRawPtr, { inner: Atom

, } impl

AtomSetOnce

where P: IntoRawPtr + FromRawPtr, { /// Create an empty `AtomSetOnce` pub fn empty() -> AtomSetOnce

{ AtomSetOnce { inner: Atom::empty(), } } /// Create a new `AtomSetOnce` from Pointer P pub fn new(value: P) -> AtomSetOnce

{ AtomSetOnce { inner: Atom::new(value), } } /// This will do a `CAS` setting the value only if it is NULL /// this will return `OK(())` if the value was written, /// otherwise a `Err(P)` will be returned, where the value was /// the same value that you passed into this function pub fn set_if_none(&self, v: P, order: Ordering) -> Option

{ self.inner.set_if_none(v, order) } /// Convert an `AtomSetOnce` into an `Atom` pub fn into_atom(self) -> Atom

{ self.inner } /// Allow access to the atom if exclusive access is granted pub fn atom(&mut self) -> &mut Atom

{ &mut self.inner } /// Check to see if an atom is None /// /// This only means that the contents was None when it was measured pub fn is_none(&self, order: Ordering) -> bool { self.inner.is_none(order) } } impl AtomSetOnce

where P: IntoRawPtr + FromRawPtr + Deref, { /// If the Atom is set, get the value pub fn get(&self, order: Ordering) -> Option<&T> { let ptr = self.inner.inner.load(order); let val = unsafe { Atom::inner_from_raw(ptr) }; val.map(|v: P| { // This is safe since ptr cannot be changed once it is set // which means that this is now a Arc or a Box. let out = unsafe { copy_lifetime(self, &*v) }; mem::forget(v); out }) } } impl AtomSetOnce> { /// If the Atom is set, get the value pub fn get_mut(&mut self, order: Ordering) -> Option<&mut T> { let ptr = self.inner.inner.load(order); let val = unsafe { Atom::inner_from_raw(ptr) }; val.map(move |mut v: Box| { // This is safe since ptr cannot be changed once it is set // which means that this is now a Arc or a Box. let out = unsafe { copy_mut_lifetime(self, &mut *v) }; mem::forget(v); out }) } } impl AtomSetOnce where T: Clone + IntoRawPtr + FromRawPtr, { /// Duplicate the inner pointer if it is set pub fn dup(&self, order: Ordering) -> Option { let ptr = self.inner.inner.load(order); let val = unsafe { Atom::inner_from_raw(ptr) }; val.map(|v: T| { let out = v.clone(); mem::forget(v); out }) } } /// This is a utility Trait that fetches the next ptr from /// an object. pub trait GetNextMut { type NextPtr; fn get_next(&mut self) -> &mut Self::NextPtr; } atom-0.4.0/tests/atom.rs010066400017500001750000000213351373702275600133660ustar0000000000000000// Copyright 2015 Colin Sherratt // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. extern crate atom; use atom::*; use std::collections::HashSet; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use std::sync::*; use std::thread; #[test] fn swap() { let a = Atom::empty(); assert_eq!(a.swap(Box::new(1u8), Ordering::AcqRel), None); assert_eq!(a.swap(Box::new(2u8), Ordering::AcqRel), Some(Box::new(1u8))); assert_eq!(a.swap(Box::new(3u8), Ordering::AcqRel), Some(Box::new(2u8))); } #[test] fn take() { let a = Atom::new(Box::new(7u8)); assert_eq!(a.take(Ordering::Acquire), Some(Box::new(7))); assert_eq!(a.take(Ordering::Acquire), None); } #[test] fn set_if_none() { let a = Atom::empty(); assert_eq!(a.set_if_none(Box::new(7u8), Ordering::Release), None); assert_eq!( a.set_if_none(Box::new(8u8), Ordering::Release), Some(Box::new(8u8)) ); } #[test] fn compare_and_swap_basics() { cas_test_basics_helper(|a, cas_val, next_val| { a.compare_and_swap(cas_val, next_val, Ordering::SeqCst) }); } #[test] fn compare_exchange_basics() { cas_test_basics_helper(|a, cas_val, next_val| { a.compare_exchange(cas_val, next_val, Ordering::SeqCst, Ordering::SeqCst) }); } #[test] fn compare_exchange_weak_basics() { cas_test_basics_helper(|a, cas_val, next_val| { a.compare_exchange_weak(cas_val, next_val, Ordering::SeqCst, Ordering::SeqCst) }); } #[test] fn compare_and_swap_threads() { cas_test_threads_helper(|a, cas_val, next_val| { a.compare_and_swap(cas_val, next_val, Ordering::SeqCst) }); } #[test] fn compare_exchange_threads() { cas_test_threads_helper(|a, cas_val, next_val| { a.compare_exchange(cas_val, next_val, Ordering::SeqCst, Ordering::SeqCst) }); } #[test] fn compare_exchange_weak_threads() { cas_test_threads_helper(|a, cas_val, next_val| { a.compare_exchange_weak(cas_val, next_val, Ordering::SeqCst, Ordering::SeqCst) }); } type TestCASFn = fn(&Atom>, Option<&Arc>, Option>) -> Result>, (Option>, *mut Arc)>; fn cas_test_basics_helper(cas: TestCASFn) { let cur_val = Arc::new("123".to_owned()); let mut next_val = Arc::new("456".to_owned()); let other_val = Arc::new("1927447".to_owned()); let a = Atom::new(cur_val.clone()); let pcur = IntoRawPtr::into_raw(cur_val.clone()); let pnext = IntoRawPtr::into_raw(next_val.clone()); for attempt in vec![None, Some(&other_val), Some(&Arc::new("wow".to_owned()))] { let res = cas(&a, attempt, Some(next_val.clone())).unwrap_err(); next_val = res.0.unwrap(); assert_eq!(res.1, pcur as *mut _); } let res = cas(&a, Some(&cur_val), Some(next_val.clone())); assert_eq!(res, Ok(Some(cur_val))); for attempt in vec![None, Some(&other_val), Some(&Arc::new("wow".to_owned()))] { let res = cas(&a, attempt, None).unwrap_err(); assert_eq!(res, (None, pnext as *mut _)); } } fn cas_test_threads_helper(cas: TestCASFn) { let cur_val = Arc::new("current".to_owned()); let next_val = Arc::new("next".to_owned()); let other_val = Arc::new("other".to_owned()); let a = Arc::new(Atom::new(cur_val.clone())); let num_threads = 10; let cas_thread = num_threads / 2; let pprevs: Vec> = (0..num_threads) .map(|i| { let a = a.clone(); let cur_val = cur_val.clone(); let next_val = next_val.clone(); let other_val = other_val.clone(); thread::spawn(move || { let cas_val = Some(if i == cas_thread { &cur_val } else { &other_val }); match cas(&a, cas_val, Some(next_val.clone())) { Ok(prev) => { let prev = prev.unwrap(); assert!(Arc::ptr_eq(&prev, &cur_val)); assert!(!Arc::ptr_eq(&prev, &next_val)); Ok(prev.into_raw() as usize) } Err((_, pprev)) => Err(pprev as usize), } }) }) .map(|handle| handle.join().unwrap()) .collect(); assert_eq!(pprevs.iter().filter(|pprev| pprev.is_ok()).count(), 1); let uniq_pprevs: HashSet<_> = pprevs .into_iter() .map(|pprev| pprev.unwrap_or_else(|pprev| pprev) as *mut _) .collect(); assert!(uniq_pprevs.contains(&cur_val.into_raw())); assert!(!uniq_pprevs.contains(&other_val.into_raw())); assert_eq!(a.take(Ordering::Relaxed), Some(next_val)); } #[derive(Clone)] struct Canary(Arc); impl Drop for Canary { fn drop(&mut self) { self.0.fetch_add(1, Ordering::SeqCst); } } #[test] fn ensure_drop() { let v = Arc::new(AtomicUsize::new(0)); let a = Box::new(Canary(v.clone())); let a = Atom::new(a); assert_eq!(v.load(Ordering::SeqCst), 0); drop(a); assert_eq!(v.load(Ordering::SeqCst), 1); } #[test] fn ensure_drop_arc() { let v = Arc::new(AtomicUsize::new(0)); let a = Arc::new(Canary(v.clone())); let a = Atom::new(a); assert_eq!(v.load(Ordering::SeqCst), 0); drop(a); assert_eq!(v.load(Ordering::SeqCst), 1); } #[test] fn ensure_send() { let atom = Arc::new(Atom::empty()); let wait = Arc::new(Barrier::new(2)); let w = wait.clone(); let a = atom.clone(); thread::spawn(move || { a.swap(Box::new(7u8), Ordering::AcqRel); w.wait(); }); wait.wait(); assert_eq!(atom.take(Ordering::Acquire), Some(Box::new(7u8))); } #[test] fn get() { let atom = Arc::new(AtomSetOnce::empty()); assert_eq!(atom.get(Ordering::Acquire), None); assert_eq!(atom.set_if_none(Box::new(8u8), Ordering::Release), None); assert_eq!(atom.get(Ordering::Acquire), Some(&8u8)); } #[test] fn get_arc() { let atom = Arc::new(AtomSetOnce::empty()); assert_eq!(atom.get(Ordering::Acquire), None); assert_eq!(atom.set_if_none(Arc::new(8u8), Ordering::Release), None); assert_eq!(atom.get(Ordering::Acquire), Some(&8u8)); let v = Arc::new(AtomicUsize::new(0)); let atom = Arc::new(AtomSetOnce::empty()); atom.get(Ordering::Acquire); atom.set_if_none(Arc::new(Canary(v.clone())), Ordering::Release); atom.get(Ordering::Acquire); drop(atom); assert_eq!(v.load(Ordering::SeqCst), 1); } #[derive(Debug)] struct Link { next: Option>, value: u32, } impl Link { fn new(v: u32) -> Box { Box::new(Link { next: None, value: v, }) } } impl GetNextMut for Box { type NextPtr = Option>; fn get_next(&mut self) -> &mut Option> { &mut self.next } } #[test] fn lifo() { let atom = Atom::empty(); for i in 0..100 { let x = atom.replace_and_set_next(Link::new(99 - i), Ordering::Relaxed, Ordering::AcqRel); assert_eq!(x, i == 0); } let expected: Vec = (0..100).collect(); let mut found = Vec::new(); let mut chain = atom.take(Ordering::Acquire); while let Some(v) = chain { found.push(v.value); chain = v.next; } assert_eq!(expected, found); } #[allow(dead_code)] struct LinkCanary { next: Option>, value: Canary, } impl LinkCanary { fn new(v: Canary) -> Box { Box::new(LinkCanary { next: None, value: v, }) } } impl GetNextMut for Box { type NextPtr = Option>; fn get_next(&mut self) -> &mut Option> { &mut self.next } } #[test] fn lifo_drop() { let v = Arc::new(AtomicUsize::new(0)); let canary = Canary(v.clone()); let mut link = LinkCanary::new(canary.clone()); link.next = Some(LinkCanary::new(canary.clone())); let atom = Atom::empty(); atom.replace_and_set_next(link, Ordering::Relaxed, Ordering::AcqRel); assert_eq!(1, v.load(Ordering::SeqCst)); drop(atom); assert_eq!(2, v.load(Ordering::SeqCst)); } #[test] fn borrow() { let a = Atom::new(&5); assert_eq!(a.swap(&7, Ordering::Relaxed), Some(&5)); assert_eq!(a.take(Ordering::Relaxed), Some(&7)); }