A standard library for the client-side Web

Last update: Jun 16, 2022

Build Status Join the chat at https://gitter.im/stdweb-rs/stdweb

A standard library for the client-side Web

Documentation

The goal of this crate is to provide Rust bindings to the Web APIs and to allow a high degree of interoperability between Rust and JavaScript.

Donate

Become a patron

Patrons

This software was brought to you thanks to these wonderful people:

  • Embark Studios
  • Joe Narvaez
  • Eduard Knyshov
  • Anselm Eickhoff
  • Johan Andersson
  • Stephen Sugden
  • is8ac

Thank you!

Examples

You can directly embed JavaScript code into Rust:

let message = "Hello, 世界!";
let result = js! {
    alert( @{message} );
    return 2 + 2 * 2;
};

println!( "2 + 2 * 2 = {:?}", result );

Closures are also supported:

let print_hello = |name: String| {
    println!( "Hello, {}!", name );
};

js! {
    var print_hello = @{print_hello};
    print_hello( "Bob" );
    print_hello.drop(); // Necessary to clean up the closure on Rust's side.
}

You can also pass arbitrary structures thanks to serde:

#[derive(Serialize)]
struct Person {
    name: String,
    age: i32
}

js_serializable!( Person );

js! {
    var person = @{person};
    console.log( person.name + " is " + person.age + " years old." );
};

This crate also exposes a number of Web APIs, for example:

let button = document().query_selector( "#hide-button" ).unwrap().unwrap();
button.add_event_listener( move |_: ClickEvent| {
    for anchor in document().query_selector_all( "#main a" ) {
        js!( @{anchor}.style = "display: none;"; );
    }
});

Exposing Rust functions to JavaScript is supported too:

#[js_export]
fn hash( string: String ) -> String {
    let mut hasher = Sha1::new();
    hasher.update( string.as_bytes() );
    hasher.digest().to_string()
}

Then you can do this from Node.js:

var hasher = require( "hasher.js" ); // Where `hasher.js` is generated from Rust code.
console.log( hasher.hash( "Hello world!" ) );

Or you can take the same .js file and use it in a web browser:

<script src="hasher.js"></script>
<script>
    Rust.hasher.then( function( hasher ) {
        console.log( hasher.hash( "Hello world!" ) );
    });
</script>

If you're using Parcel you can also use our experimental Parcel plugin; first do this in your existing Parcel project:

$ npm install --save parcel-plugin-cargo-web

And then simply:

import hasher from "./hasher/Cargo.toml";
console.log( hasher.hash( "Hello world!" ) );

Design goals

  • Expose a full suite of Web APIs as exposed by web browsers.
  • Try to follow the original JavaScript conventions and structure as much as possible, except in cases where doing otherwise results in a clearly superior design.
  • Be a building block from which higher level frameworks and libraries can be built.
  • Make it convenient and easy to embed JavaScript code directly into Rust and to marshal data between the two.
  • Integrate with the wider Rust ecosystem, e.g. support marshaling of structs which implement serde's Serializable.
  • Put Rust in the driver's seat where a non-trivial Web application can be written without touching JavaScript at all.
  • Allow Rust to take part in the upcoming WebAssembly (re)volution.
  • Make it possible to trivially create standalone libraries which are easily callable from JavaScript.

Getting started

Take a look at some of the examples:

  • examples/minimal - a totally minimal example which calls alert
  • examples/todomvc - a naively implemented TodoMVC application; shows how to call into the DOM
  • examples/hasher - shows how to export Rust functions to JavaScript and how to call them from a vanilla web browser environment or from Nodejs
  • examples/hasher-parcel - shows how to import and call exported Rust functions in a Parcel project
  • pinky-web - an NES emulator; you can play with the precompiled version here

The API documentation is also available for you to look at.

Running the examples

  1. Install cargo-web:

    $ cargo install -f cargo-web
    
  2. Go into examples/todomvc and start the example using one of these commands:

    • Compile to WebAssembly using Rust's native WebAssembly backend:

      $ cargo web start --target=wasm32-unknown-unknown
      
    • Compile to asm.js using Emscripten:

      $ cargo web start --target=asmjs-unknown-emscripten
      
    • Compile to WebAssembly using Emscripten:

      $ cargo web start --target=wasm32-unknown-emscripten
      
  3. Visit http://localhost:8000 with your browser.

For the *-emscripten targets cargo-web is not necessary, however the native wasm32-unknown-unknown which doesn't need Emscripten requires cargo-web to work!

Changelog

  • stdweb 0.4.20

    • Compatibility with the newest wasm-bindgen
    • New events:
      • FullscreenChangeEvent
  • stdweb 0.4.19

    • New methods:
      • Document::fullscreen_enabled
      • Document::fullscreen_element
      • InputElement::selection_start
      • InputElement::selection_end
      • InputElement::set_selection_start
      • InputElement::set_selection_end
      • Object::to_iter
      • Window::confirm
    • &Arrays can now be converted to Vecs through TryFrom
    • The runtime should now be compatible with newer versions of Emscripten
    • The unstable futures-related APIs were updated to work with the latest nightlies
    • The syn dependency was updated to version 1
  • stdweb 0.4.18

    • The js! macro can now be imported with an use
    • New events:
      • BeforeUnloadEvent
      • UnloadEvent
    • New methods:
      • IBlob::slice
      • IBlob::slice_with_content_type
      • IWindowOrWorker::set_clearable_timeout
  • stdweb 0.4.17

    • The unstable futures-related APIs were updated to work with the latest nightlies
  • stdweb 0.4.16

    • Initial wasm-bindgen compatibility; you can now use stdweb in projects using wasm-bindgen
    • Minimum supported Rust version is now 1.33.0
    • Minimum required cargo-web version is now 0.6.24
  • stdweb 0.4.15

    • The unstable futures-related APIs were updated to work with the latest nightlies
    • New types:
      • FormData
      • FormDataEntry
      • MouseButtonsState
    • New methods:
      • Blob::new
  • stdweb 0.4.14

    • The js! macro now generates slightly more efficient code if you're not returning anything from your JS snippet. This makes it unnecessary to add the @(no_return) annotation in the vast majority of cases.
    • New types:
      • File
  • stdweb 0.4.13

    • Fixed the procedural js! macro's whitespace handling
    • New types:
      • ITouchEvent
      • Touch
      • TouchType
    • New events:
      • TouchEvent
      • TouchMove
      • TouchLeave
      • TouchEnter
      • TouchEnd
      • TouchCancel
      • TouchStart
    • New methods:
      • XmlHttpRequest::set_response_type
  • stdweb 0.4.12

    • Improved diagnostics when trying to compile for the wasm32-unknown-unknown target without cargo-web
  • stdweb 0.4.11

    • The minimum required Rust version is now 1.30.1
    • The minimum required cargo-web version is now 0.6.22
    • wasm32-unknown-unknown is now officially supported on stable Rust
    • Debug builds on wasm32-unknown-unknown are now supported
    • The js! macro is now partially implemented using a procedural macro
    • String decoding/encoding is now a lot faster due to the use of native codec APIs
    • New methods:
      • Document::import_node
      • IElement::slot
      • IElement::attach_shadow
      • IElement::shadow_root
    • New types:
      • ISlotable
      • ShadowRoot
      • ShadowRootMode
      • TemplateElement
      • SlotElement
    • New events:
      • SlotChangeEvent
    • IParentNode::query_selector and IParentNode::query_selector_all now return a proper error type
  • stdweb 0.4.10, stdweb-derive 0.5.1

    • New methods:
      • IElement::insert_adjacent_html
      • IElement::insert_html_before
      • IElement::insert_html_after
      • IElement::prepend_html
      • IElement::append_html
      • IElement::namespace_uri
      • IElement::closest
      • Document::create_element_ns
      • Window::get_selection
    • New types:
      • AbortError
      • SelectionType
      • Selection
      • Range
    • The error messages for failed type conversions are now improved
    • The error type of failed conversions (when using .try_into()/.try_from()) is now convertible into a TypeError
    • Aggregate error types (like, e.g. DrawImageError) are now serializable through the js! macro
    • TypeError is now fixed (it was incorrectly treated as a DOMException)
    • Number can now be converted into f64 with .into()/.from()
    • Added Mut, which is a new wrapper type for safely passing FnMut closures into the js! macro; it is optional for now, however the usage of this wrapper type will be mandatory in the future!
    • FnMut closures cannot be called recursively anymore
    • #[derive(ReferenceType)] now supports a limited subset of generic types
    • Asynchronous unit tests are now supported with a new #[async_test] attribute macro (nightly only)
    • Updated to futures 0.3 (nightly only)
  • stdweb 0.4.9, stdweb-derive 0.5.0

    • Performance improvements; serialization through serde is now twice as fast
    • New events:
      • ScrollEvent
      • DragRelatedEvent
      • DragEvent
      • DragStartEvent
      • DragEndEvent
      • DragEnterEvent
      • DragLeaveEvent
      • DragOverEvent
      • DragExitEvent
      • DragDropEvent
    • New types:
      • DataTransfer
      • EffectAllowed
      • DropEffect
      • DataTransferItemList
      • DataTransferItem
      • DataTransferItemKind
      • IDragEvent
    • Values can now be converted to Option< Serde< T > > with try_into
    • Deserialization of numbers through serde now works in the majority of cases allowing types other than i32 and f64 to be used
    • All of the events are now more strongly-typed
      • Previously in was possible to deserialize e.g. a keyup event as a KeyDownEvent since only the event's JS type was checked and both keyup and keydown share the same JS type (KeyboardEvent). From now on the type field of the event is also checked, so such conversions are not allowed anymore.
  • 0.4.8

    • Fixed compilation on the newest nightly when targeting wasm32-unknown-unknown
    • New events:
      • PointerLockChangeEvent
      • PointerLockErrorEvent
      • MouseWheelEvent
    • New types:
      • MouseWheelDeltaMode
      • XhrResponseType
    • New methods:
      • XmlHttpRequest::raw_response
      • Window::device_pixel_ratio
      • Document::pointer_lock_element
      • Document::exit_pointer_lock
  • 0.4.7

    • New events:
      • AuxClickEvent
      • MouseEnterEvent
      • MouseLeaveEvent
      • ContextMenuEvent
      • SelectionChangeEvent
    • New types:
      • FileList
      • FileReaderReadyState
    • Implement gamepad APIs:
      • Gamepad
      • GamepadButton
      • GamepadButtonMapping
      • GamepadEvent
    • Fixed CanvasRenderingContext2d::clear_rect
    • Fixed a leak when creating TypedArrays from Vecs and ArrayBuffers.
  • 0.4.6

    • Fix docs.rs again
    • New types:
      • SubmitEvent
      • IChildNode
    • Fix CanvasElement::to_data_url
  • 0.4.5

    • New types:
      • DocumentFragment
      • SelectElement
      • OptionElement
      • HtmlCollection
    • New methods:
      • Node::from_html
      • Value::is_null
    • Expose enums:
      • SocketMessageData
      • NodeType
    • Update to futures 0.2
  • 0.4.4

    • Fix docs.rs (hopefully).
    • New methods:
      • Location::origin
      • Location::protocol
      • Location::host
      • Location::hostname
      • Location::port
      • Location::pathname
      • Location::search
    • These now return SecurityError in the error case:
      • Location::hash
      • Location::href
  • 0.4.3

    • Objects which cannot be used as keys in a WeakMap should be supported now (e.g. some of the WebGL-related objects under Firefox)
    • New methods:
      • Element::get_bounding_client_rect
      • Element::scroll_top
      • Element::scroll_left
      • Window::page_x_offset
      • Window::page_y_offset
      • NodeList::item
      • Document::body
      • Document::head
      • Document::title
      • Document::set_title
      • IMouseEvent::offset_x
      • IMouseEvent::offset_y
    • Expose more canvas related types:
      • CompositeOperation
      • LineCap
      • LineJoin
      • Repetition
      • TextAlign
      • TextBaseline
    • Expose canvas related error types: AddColorStopError, DrawImageError, GetImageDataError
    • New events:
      • MouseOverEvent
      • MouseOutEvent
      • PointerOverEvent
      • PointerEnterEvent
      • PointerDownEvent
      • PointerMoveEvent
      • PointerUpEvent
      • PointerCancelEvent
      • PointerOutEvent
      • PointerLeaveEvent
      • GotPointerCaptureEvent
      • LostPointerCaptureEvent
    • New interface for pointer events: IPointerEvent
  • 0.4.2

    • Fixed a leak when deserializing references
    • Fixed CanvasRenderingContext2d::get_canvas
    • Exposed FillRule and SocketReadyState
    • New attribute related methods added to IElement
    • New Date bindings
  • 0.4.1

    • Support for newest nightly Rust on wasm32-unknown-unknown
    • Exposed SocketBinaryType enum
    • New canvas APIs:
      • Numerous new methods for CanvasRenderingContext2d
      • New types: CanvasGradient, CanvasPattern, CanvasStyle, ImageData, TextMetrics
    • New error types: IndexSizeError, NotSupportedError, TypeError
  • 0.4

    • (breaking change) Removed Array and Object variants from Value; these are now treated as References
    • (breaking change) The Value has an extra variant: Symbol
    • (breaking change) Removed:
      • InputElement::set_kind
      • InputElement::files
    • (breaking change) Renamed:
      • KeydownEvent -> KeyDownEvent
      • KeyupEvent -> KeyUpEvent
      • KeypressEvent -> KeyPressEvent
      • ReadyState -> FileReaderReadyState
      • InputElement::value -> InputElement::raw_value
      • InputElement::set_value -> InputElement::set_raw_value
    • (breaking change) ArrayBuffer::new now takes an u64 argument
    • (breaking change) InputElement::set_raw_value now takes &str instead of Into< Value >
    • (breaking change) Changed return types:
      • Every method which returned usize now returns u32
      • INode::remove_child now returns Node in the Ok case
      • The following now return an u64:
        • ArrayBuffer::len
      • The following now return an i32 instead of f64:
        • IMouseEvent::client_x
        • IMouseEvent::client_y
        • IMouseEvent::movement_x
        • IMouseEvent::movement_y
        • IMouseEvent::screen_x
        • IMouseEvent::screen_y
      • The following now return a Result:
        • INode::insert_before
        • INode::replace_child
        • INode::clone_node
        • StringMap::insert
        • TokenList::add
        • TokenList::remove
        • Document::create_element
        • IEventTarget::dispatch_event
        • FileReader::read_as_text
        • FileReader::read_as_array_buffer
        • FileReader::read_as_text
        • History::replace_state
        • History::go
        • History::back
        • History::forward
        • Location::href
        • Location::hash
        • CanvasElement::to_data_url
        • CanvasElement::to_blob
        • ArrayBuffer::new
      • INode::base_uri now returns a String instead of Option< String >
      • InputElement::raw_value now returns a String instead of Value
    • (breaking change) INode::inner_text was moved to IHtmlElement::inner_text
    • (breaking change) Document::query_selector and Document::query_selector_all were moved to IParentNode
    • (breaking change) IElement::query_selector and IElement::query_selector_all were moved to IParentNode
    • (breaking change) Document::get_element_by_id was moved to INonElementParentNode
    • (breaking change) A blanket impl for converting between arbitrary reference-like objects using TryFrom/TryInto has been removed
    • When building using a recent cargo-web it's not necessary to call stdweb::initialize nor stdweb::event_loop anymore
    • Support for cdylib crates on wasm32-unknown-unknown
    • New bindings:
      • XmlHttpRequest
      • WebSocket
      • MutationObserver
      • History
      • TextAreaElement
      • CanvasElement
    • New event types:
      • MouseDownEvent
      • MouseUpEvent
      • MouseMoveEvent
      • PopStateEvent
      • ResizeEvent
      • ReadyStateChange
      • SocketCloseEvent
      • SocketErrorEvent
      • SocketOpenEvent
      • SocketMessageEvent
    • Initial support for the Canvas APIs
    • New traits: ReferenceType and InstanceOf
    • Add #[derive(ReferenceType)] in stdweb-derive crate; it's now possible to define custom API bindings outside of stdweb
    • Add #[js_export] procedural attribute (wasm32-unknown-unknown only)
    • Add DomException and subtypes for passing around JavaScript exceptions
    • IElement now inherits from INode
    • Every interface now inherits from ReferenceType
    • Add stdweb::traits module to act as a prelude for use-ing all of our interface traits
    • Add console! macro
    • Most types now implement PartialEq and Eq
  • 0.3

    • (breaking change) Deleted ErrorEvent methods
    • (breaking change) Renamed:
      • LoadEvent -> ResourceLoadEvent
      • AbortEvent -> ResourceAbortEvent
      • ErrorEvent -> ResourceErrorEvent
    • Add UnsafeTypedArray for zero cost slice passing to js!
    • Add Once for passing FnOnce closures to js!

License

Licensed under either of

at your option.

Snippets of documentation which come from Mozilla Developer Network are covered under the CC-BY-SA, version 2.5 or later.

Contributing

See CONTRIBUTING.md

GitHub

https://github.com/koute/stdweb
Comments
  • 1. Adding in Promises

    Fixes #72

    @koute @CryZe This is untested and is definitely not ready to merge.

    But I wanted to at least get started on adding in Promise support to stdweb. This pull request adds in the ability to convert any JS Promise into a Rustified Futurified version of that Promise. This conversion happens automatically with the TryFrom<Value> trait.

    Please look this over and let me know if you see anything weird, or anything that can be improved.

    Reviewed by Pauan at 2018-02-03 01:44
  • 2. Fix Promise memory leak

    As explained in the documentation, if the Promise never succeeds / fails then the callback will never be called, and it will leak memory. This pull request fixes that.

    Now the done method returns a DoneHandle. When the DoneHandle is dropped it will drop the callback, thus freeing the memory (at least on the Rust side).

    Reviewed by Pauan at 2018-02-15 19:37
  • 3. [Question] Are there any mechanisms to pass a result of Promise into WASM(Rust) code? And how do you use it?

    Hi.

    I want to pass a result of JS Promise into Rust code like the below.

    let result = js! { await asyncFunc(@{some_value}) };
    

    I tried such a code but got an error "SyntaxError: Unexpected identifier 'asyncFunc'" when loading generated js file.

    I should use rather Promise but I have no idea how I can take the result out from js! macro.

    Reviewed by y-ich at 2018-02-27 03:12
  • 4. Web Components: Shadow Dom + Template Element

    Rationale

    With the landing of Web Components in Firefox 63, all major browsers will have web components support on by default in a couple of weeks(when Firefox 63 becomes stable). Web Components can provide better performance especially on mobile platforms comparing to other JavaScript-based solutions. I think now it is a good time to implement Web Components support.

    Outcome

    Web Components consists of Template Element, Shadow DOM, Custom Element and HTML Imports. This pull request aims at implementing all of them except HTML Imports. There are concerns about the disconnection between ES6 Modules and HTML Imports and thus Safari and Firefox refuse to implement it. Frameworks like Polymer used to use HTML Imports has moved away from it. Chrome also deprecated HTML Imports. It may need major revamp before it gains any adoption from browser vendors. Hence, I've decided to not include HTML imports in this pull request.

    Steps

    • [x] Template Element
      • [x] TemplateElement
      • [x] Document.import_node
      • [x] Tests
    • [x] Shadow DOM
      • [x] Slot
        • [x] SlotElement
        • [x] ISlotable
        • [x] SlotChangeEvent
      • [x] ShadowRootMode
      • [x] ShadowRoot
      • [x] IElement.attach_shadow
      • [x] IElement.shadow_root
      • [x] Tests
    • [ ] Custom Elements(Withdrawn due to unexpected circumstances)

    (I didn't write tests because I don't have Chrome on my computer. I'll make them up eventually.)

    Unsolved Question

    How should custom elements be constructed? Approach 1:

    #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
    #[reference(instance_of = "MyElement")]
    #[reference(subclass_of(EventTarget, Node, Element, HtmlElement))]
    #[custom_element(name = "my-element", extends = "HTMLElement")]
    struct MyElement(Reference);
    
    impl ICustomElement for MyElement { // HtmlElement and IHtmlElement are already occupied.
        fn inited(&self) {
            // JavaScript Constructor Called
        }
        fn connected(&self) {
            // HTMLElement.connectedCallback
        }
        fn attr_changed(&self, attr_name: String, before: String, after: String) {
            // HTMLElement.attributeChangedCallback
        }
        fn adopted(&self) {
            // HTMLElement.adoptedCallback
        }
        fn disconnected(&self) {
            // HTMLElement.disconnectedCallback
        }
    
        fn observed_attrs(&self) -> Vec<String> {
            // vec!["name".to_owned(), "class".to_owned()]
        }
    }
    
    fn define_custom_elements() {
        // ...
        window().custom_elements().define(MyElement);
        // ...
    }
    

    Pros:

    • It allows custom elements to subclass other elements(e.g.: HTMLTextareaElement).
    • It looks like the original api.

    Cons:

    • I don't know how to implement this.
      • Is there any other way to construct a JavaScript class than js! macro?
      • How to downcast JavaScript types to rust structs at runtime?
      • Will [reference(instance_of = "MyElement")] work if the class is not defined at the time wasm file is initiated?

    Approach 2:

    fn define_custom_elements() {
        // ...
        CustomElementBuilder::new("my-element")
            .on_inited(|element| {})
            .on_connected(|| {})
            .on_attr_changed(|attr_name, before, after| {})
            .on_adopted(|| {})
            .on_disconnected(|| panic!())
            .watch_attrs(["name", "class"])
            .define().unwrap();
        // ...
    }
    

    Pros:

    • It is easy to implement. Just js! all javascript code inside define().

    Cons:

    • It's not possible to subclass other elements like HTMLTextareaElement.

    See also: #32

    Reviewed by futursolo at 2018-10-19 23:08
  • 5. Implement fallback for references which cannot be stored in a WeakMap

    Fixes #92

    This implements a fallback mechanism using a normal Map if attempting to store an object in the WeakMap throws an exception - objects stored here are explicitly removed when their reference count reaches zero, meaning that there are no leaks, but that the "stable ID" guarantee does not hold for these specific objects.

    This likely comes with a performance penalty due to the use of exception handling.

    Personally I would prefer the "stable ID" guarantee to be dropped entirely from webcore, and instead a WeakMap type was exposed so that stable IDs could still be achieved by opting in for specific objects.

    Reviewed by Diggsey at 2018-04-01 19:01
  • 6. Complete CanvasRenderingContext2D API

    I plan on adding all of the methods and properties of CanvasRenderingContext2D. Currently a work in progress but I've opened this PR to get some feedback on the implementation of certain functions.

    Starting with clip and create_pattern_image where I had to create Enums.

    As well as in createPattern which takes a CanvasImageSource but I've currently only implemented the ImageElement as create_pattern_image.

    Reviewed by teovoinea at 2018-01-27 17:06
  • 7. fix #199: add Node::from_html

    fix #199

    Outstanding question:

    • Should the "root element" be ~~div~~ span?
    • Should it be configurable in some way (id, let the user specify the tag, let the user insert a node?)
    • should this be implemented as Node::set_inner_html instead (or can we have both)?
    Reviewed by vitiral at 2018-04-11 19:08
  • 8. added requestAnimationFrame to window

    I added the https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame to window. I ended up copying the funcall_adapter function over temporarily to verify that it actually works, but I'm assuming there should be some sort of shared module that it can go in that would be better?

    Reviewed by keeslinp at 2017-12-18 01:15
  • 9. Futures 0.3

    It was actually a lot easier than I thought to convert from Futures 0.2 to 0.3 (it required very little code changes).

    Breaking changes:

    • Now uses Futures 0.3 rather than 0.2 (which has various breaking changes of its own).
    • PromiseFuture::spawn_local has been changed to spawn_local
    • PromiseFuture::print_error_panic has been changed to print_error_panic
    • The experimental_features_which_may_break_on_minor_version_bumps and futures-support features now require Nightly Rust.

    New additions:

    • It's now possible to use async + await! + join! + try_join! syntax :tada: (I added a promise example which demonstrates this).
    • New unwrap_future function (which internally uses print_error_panic)

    The breaking changes and new additions only affect people who are using the experimental_features_which_may_break_on_minor_version_bumps feature, so this does not require a major version bump.

    Reviewed by Pauan at 2018-09-17 12:34
  • 10. Building on top of wasm-bindgen?

    This topic has come up from time to time, but I'd be curious if it'd be good to make this official? Would stdweb be up for officially moving in the direction (eventually) of building on top of wasm-bindgen?

    If so, I'd be more than willing to help fill out more information and work with y'all to make sure we can handle everything. We mentioned during the last rustwasm working group meeting that I'd meet with @Pauan and have some discussion on Discord, but I wasn't able to reach them just afterwards :(. In any case, if this sounds like a good idea, it's probably best to close this an open a more official tracking issue next.

    Reviewed by alexcrichton at 2019-01-10 19:25
  • 11. Adding in timer Futures (e.g. setTimeout and setInterval)

    @koute @CryZe This is not ready to merge yet. It still needs an implementation of setInterval, and also documentation.

    I want to get feedback on two things:

    1. The code for WaitFuture. In particular, is it okay to call .drop() on a Once callback multiple times?

    2. I want to implement setInterval, however there are actually many different ways to implement it.

      Let's say you use interval(1000) to create a Stream, it might behave in any of these ways:

      • Every 1 second it sends a () message, regardless of whether the consumer is ready or not. These messages will be buffered, and when the consumer is ready it might pull multiple () messages at once.

      • Same behavior as above, except it only buffers a single message, so when the consumer is ready it will never pull more than 1 message at once.

      • After the consumer pulls a message, it will wait 1 second before it sends another message. In other words, it's guaranteed that the consumer will not receive a message more than once every 1 second (no matter how fast or slowly it pulls).

      It seems to me that all three of these behaviors are useful (in different situations), so we should probably have three separate functions. What should these functions be called?

    Reviewed by Pauan at 2018-02-14 16:26
  • 12. Panic on Firefox with Trunk

    I was experimenting with using GilRs on WASM with Trunk using the following code:

    use std::{cell::RefCell, rc::Rc};
    use gilrs::Event;
    use log::info;
    use wasm_bindgen::{prelude::*, JsCast};
    
    fn window() -> web_sys::Window {
        web_sys::window().expect("Platform does not have a global window.")
    }
    
    fn request_animation_frame(f: &Closure<dyn FnMut()>) {
        window()
            .request_animation_frame(f.as_ref().unchecked_ref())
            .expect("`requestAnimationFrame` should succeed");
    }
    
    fn game_loop(mut callback: impl FnMut() + 'static) {
        std::panic::set_hook(Box::new(console_error_panic_hook::hook));
        console_log::init_with_level(log::Level::Info).expect("Couldn't setup console logging");
    
        let f = Rc::new(RefCell::new(None));
        let g = f.clone();
    
        *g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
            callback();
            request_animation_frame(f.borrow().as_ref().unwrap());
        }) as Box<dyn FnMut()>));
    
        info!("Starting game loop");
        request_animation_frame(g.borrow().as_ref().unwrap());
    }
    
    fn main() -> Result<(), Box<dyn std::error::Error>> {
        let mut context = gilrs::Gilrs::new()?;
    
        game_loop(move || {
            info!("game_loop");
            while let Some(Event { id, event, time}) = context.next_event() {
                info!("Gamepad event");
                // info!("{:?}", id);
            }
        });
    
        Ok(())
    }
    

    The code runs fine as long as the connected gamepad doesn't have any inputs. As soon as the gamepad gets an input, the code panics with the following:

    Panic location: /home/ben/.cargo/registry/src/github.com-1ecc6299db9ec823/stdweb-0.4.20/src/webcore/serialization.rs:447 inline279.js:1:108
        __cargo_web_snippet_72fc447820458c720c68d0d8e078ede631edd723 http://localhost:8080/snippets/stdweb-bb142200b065bd55/inline279.js:1
        __wbg_cargowebsnippet72fc447820458c720c68d0d8e078ede631edd723_ece3da0a4474dbeb http://localhost:8080/index-44e15f7f4b7059be.js:429
        hfc584dac876d521b http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:567993
        h11bcb30f712fdf5b http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:675817
        hd829486609ce1dfc http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:690973
        h98ec191c18086a09 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:302453
        h606d7c7f7a423b98 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:454051
        h9b985a293aac4ce1 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:561075
        ha03abef02a8b70fd http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:746856
        rust_begin_unwind http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:715965
        h6314b5c91abe7349 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:730725
        hec1fc057bd0baf0b http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:694808
        <stdweb::webcore::serialization::SerializedValue as core::convert::From<stdweb::webcore::serialization::SerializedUntaggedReference>>::from::hadfbae9d235f25d7 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:357571
        <T as core::convert::Into<U>>::into::h5a573d61e2a7eb6e http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:568628
        <stdweb::webcore::value::Reference as stdweb::webcore::serialization::JsSerialize>::_into_js::hc4c09f414aa3eb25 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:679509
        <&T as stdweb::webcore::serialization::JsSerialize>::_into_js::h85c64cc956c40e8d http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:707989
        <stdweb::webcore::newtype::Newtype<(stdweb::webcore::serialization::NonFunctionTag,()),T> as stdweb::webcore::serialization::JsSerializeOwned>::into_js_owned::h5d20b7dcb6d87257 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:657841
        heaa01a07f9cd69d9 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:304545
        h67e64ad48dc99139 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:54876
        h91b9f80778aea007 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:618855
        core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &mut F>::call_once::hd4a412cd0b519899 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:555100
        ha00841e5932f2bc4 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:344169
        <core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::next::h352aa1033bc5ab60 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:576477
        <alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter::h7a1b3705b436b9b7 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:218444
        <alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter::h57e586fadfc94a89 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:516655
        <alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter::h547de20f16ac3be1 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:468799
        h099f28b8da9dd9e8 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:516997
        hc5395bde68faa4b7 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:49546
        h600223be596d5476 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:717220
        h72b1789ec4d25374 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:42919
        h0f2fad8861d4473a http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:187492
        h9806841f81972af8 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:177300
        h8d4b07a2975bb5a0 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:477376
        <dyn core::ops::function::FnMut<()>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hd01aec6e6501a09e http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:513139
        __wbg_adapter_20 http://localhost:8080/index-44e15f7f4b7059be.js:222
        real http://localhost:8080/index-44e15f7f4b7059be.js:207
        (Async: FrameRequestCallback)
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:354
        handleError http://localhost:8080/index-44e15f7f4b7059be.js:257
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:353
        hdcbe2455b4a75a5c http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:388341
        h152f11a925cb67a2 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:467811
        h8d4b07a2975bb5a0 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:477517
        <dyn core::ops::function::FnMut<()>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hd01aec6e6501a09e http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:513139
        __wbg_adapter_20 http://localhost:8080/index-44e15f7f4b7059be.js:222
        real http://localhost:8080/index-44e15f7f4b7059be.js:207
        (Async: FrameRequestCallback)
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:354
        handleError http://localhost:8080/index-44e15f7f4b7059be.js:257
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:353
        hdcbe2455b4a75a5c http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:388341
        h152f11a925cb67a2 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:467811
        h8d4b07a2975bb5a0 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:477517
        <dyn core::ops::function::FnMut<()>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hd01aec6e6501a09e http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:513139
        __wbg_adapter_20 http://localhost:8080/index-44e15f7f4b7059be.js:222
        real http://localhost:8080/index-44e15f7f4b7059be.js:207
        (Async: FrameRequestCallback)
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:354
        handleError http://localhost:8080/index-44e15f7f4b7059be.js:257
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:353
        hdcbe2455b4a75a5c http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:388341
        h152f11a925cb67a2 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:467811
        h8d4b07a2975bb5a0 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:477517
        <dyn core::ops::function::FnMut<()>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hd01aec6e6501a09e http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:513139
        __wbg_adapter_20 http://localhost:8080/index-44e15f7f4b7059be.js:222
        real http://localhost:8080/index-44e15f7f4b7059be.js:207
        (Async: FrameRequestCallback)
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:354
        handleError http://localhost:8080/index-44e15f7f4b7059be.js:257
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:353
        hdcbe2455b4a75a5c http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:388341
        h152f11a925cb67a2 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:467811
        h8d4b07a2975bb5a0 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:477517
        <dyn core::ops::function::FnMut<()>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hd01aec6e6501a09e http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:513139
        __wbg_adapter_20 http://localhost:8080/index-44e15f7f4b7059be.js:222
        real http://localhost:8080/index-44e15f7f4b7059be.js:207
        (Async: FrameRequestCallback)
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:354
        handleError http://localhost:8080/index-44e15f7f4b7059be.js:257
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:353
        hdcbe2455b4a75a5c http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:388341
        h152f11a925cb67a2 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:467811
        h8d4b07a2975bb5a0 http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:477517
        <dyn core::ops::function::FnMut<()>+Output = R as wasm_bindgen::closure::WasmClosure>::describe::invoke::hd01aec6e6501a09e http://localhost:8080/index-44e15f7f4b7059be_bg.wasm:513139
        __wbg_adapter_20 http://localhost:8080/index-44e15f7f4b7059be.js:222
        real http://localhost:8080/index-44e15f7f4b7059be.js:207
        (Async: FrameRequestCallback)
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:354
        handleError http://localhost:8080/index-44e15f7f4b7059be.js:257
        __wbg_requestAnimationFrame_8e3c7028c69ebaef http://localhost:8080/index-44e15f7f4b7059be.js:353
    

    The error seems to due with webcore serializing something as per the first line in the error:

    Panic location: /home/ben/.cargo/registry/src/github.com-1ecc6299db9ec823/stdweb-0.4.20/src/webcore/serialization.rs:447 inline279.js:1:108

    You can view the full code here: https://github.com/sotrh/gamepads

    I've already created an issue on the GilRs gitlab: https://gitlab.com/gilrs-project/gilrs/-/issues/118

    Reviewed by sotrh at 2022-04-09 20:58
  • 13. Fix deprecated trailing semicolons in macros

    This silences a very noisy deprecation warning from rustc:

    warning: trailing semicolon in macro used in expression position
       --> src/webcore/macros.rs:179:141
        |
    179 |   ... [$($arg_names)* $arg_name] [$($unused_arg_names)*] -> $($rest)* );
        |                                                                        ^
        |
       ::: src/webapi/form_data.rs:144:9
        |
    144 | /         js! (
    145 | |             return @{self}.has(@{name});
    146 | |         ).try_into().unwrap()
        | |_________- in this macro invocation
        |
        = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
        = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
        = note: this warning originates in the macro `$crate::_js_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
    
    Reviewed by notriddle at 2022-02-17 18:10
  • 14. Bump path-parse from 1.0.5 to 1.0.7 in /examples/hasher-parcel

    Bumps path-parse from 1.0.5 to 1.0.7.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    Reviewed by dependabot[bot] at 2021-08-10 17:40
  • 15. Bump lodash from 4.17.10 to 4.17.21 in /examples/hasher-parcel

    Bumps lodash from 4.17.10 to 4.17.21.

    Commits
    • f299b52 Bump to v4.17.21
    • c4847eb Improve performance of toNumber, trim and trimEnd on large input strings
    • 3469357 Prevent command injection through _.template's variable option
    • ded9bc6 Bump to v4.17.20.
    • 63150ef Documentation fixes.
    • 00f0f62 test.js: Remove trailing comma.
    • 846e434 Temporarily use a custom fork of lodash-cli.
    • 5d046f3 Re-enable Travis tests on 4.17 branch.
    • aa816b3 Remove /npm-package.
    • d7fbc52 Bump to v4.17.19
    • Additional commits viewable in compare view
    Maintainer changes

    This version was pushed to npm by bnjmnt4n, a new releaser for lodash since your current version.


    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    Reviewed by dependabot[bot] at 2021-05-06 22:03
  • 16. linking with `cc` failed: exit code: 1

    Hi im just trying to compile the following with stdweb

    #[macro_use]
    extern crate stdweb;
    
    fn main() {
        let message = "Hello, WASM";
        js! {
            console.log( @{message} )
        }
    }
    

    Gives me the following error linking with `cc` failed: exit code: 1 version 0.4.20

    Reviewed by ketuf at 2021-03-28 17:29
Simple file sharing with client-side encryption, powered by Rust and WebAssembly
Simple file sharing with client-side encryption, powered by Rust and WebAssembly

Hako Simple file sharing with client-side encryption, powered by Rust and WebAssembly Not feature-packed, but basic functionalities are just working.

Jun 9, 2022
Zaplib is an open-source library for speeding up web applications using Rust and WebAssembly.

⚡ Zaplib Zaplib is an open-source library for speeding up web applications using Rust and WebAssembly. It lets you write high-performance code in Rust

Jun 21, 2022
A console and web-based Gomoku written in Rust and WebAssembly
A console and web-based Gomoku written in Rust and WebAssembly

?? rust-gomoku A console and web-based Gomoku written in Rust and WebAssembly Getting started with cargo & npm Install required program, run # install

Jan 4, 2022
darkforest is a console and web-based Roguelike written in Rust and WebAssembly.
darkforest is a console and web-based Roguelike written in Rust and WebAssembly.

darkforest darkforest is a console and web-based Roguelike written in Rust and WebAssembly. Key Features TBA Quick Start TBA How To Contribute Contrib

Oct 5, 2021
Dister builds and bundles your wasm web app.

dister Dister builds and bundles your wasm web app. Installation cargo install dister Requirements wasm32-unknown-unknown target: rustup target add wa

Apr 9, 2022
Client for integrating private analytics in fast and reliable libraries and apps using Rust and WebAssembly

TelemetryDeck Client Client for integrating private analytics in fast and reliable libraries and apps using Rust and WebAssembly The library provides

Apr 20, 2022
Webassembly binding for Hora Approximate Nearest Neighbor Search Library
Webassembly binding for Hora Approximate Nearest Neighbor Search Library

hora-wasm [Homepage] [Document] [Examples] [Hora] Javascript bidding for the Hora Approximate Nearest Neighbor Search, in WebAssembly way. Features Pe

Jun 21, 2022
Compiler infrastructure and toolchain library for WebAssembly

Binaryen Binaryen is a compiler and toolchain infrastructure library for WebAssembly, written in C++. It aims to make compiling to WebAssembly easy, f

Jun 24, 2022
A simple event-driven library for parsing WebAssembly binary files

The WebAssembly binary file decoder in Rust A Bytecode Alliance project The decoder library provides lightweight and fast decoding/parsing of WebAssem

Dec 14, 2021
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

Jun 24, 2022
This is an implementation defining standard for client-side-validation

Client-side-validation Foundation Libraries This is an implementation defining standard of client-side-validation representing a set of its Foundation

Jun 17, 2022
ARM TrustZone-M example application in Rust, both secure world side and non-secure world side

ARM TrustZone-M example application in Rust, both secure world side and non-secure world side; projects are modified from generated result of cortex-m-quickstart.

May 31, 2022
A Cargo subcommand for the client-side Web
A Cargo subcommand for the client-side Web

A cargo subcommand for the client-side Web This cargo subcommand aims to make it easy and convenient to build, develop and deploy client-side Web appl

Jun 13, 2022
Dfinity's fungible token standard. Any PRs and comments are welcome,collaborate with us to build this standard

Dfinity's fungible token standard. Any PRs and comments are welcome,collaborate with us to build this standard

Jun 8, 2022
CouchDB client-side library for the Rust programming language

Chill Chill is a client-side CouchDB library for the Rust programming language, available on crates.io. It targets Rust Stable. Chill's three chief de

Mar 10, 2022
Network-agnostic, high-level game networking library for client-side prediction and server reconciliation.
Network-agnostic, high-level game networking library for client-side prediction and server reconciliation.

WARNING: This crate currently depends on nightly rust unstable and incomplete features. crystalorb Network-agnostic, high-level game networking librar

Jun 20, 2022
Everyday-use client-side map-aware Arch Linux mirror ranking tool

Rate Arch Mirrors This is a tool, which fetches mirrors, skips outdated/syncing Arch Linux mirrors, then uses info about submarine cables and internet

Jun 20, 2022
A client-side gRPC channel implementation for tonic

ginepro ginepro provides client-side gRPC load-balancing out of the box by enriching tonic ‘s channel with periodic service discovery. Overview ginepr

May 31, 2022
A Rust CLI tool that helps you enforce Git policies through Git hooks both server and client side

GitPolicyEnforcer This is a command line utility written in Rust, that helps you utilize Git hooks, to enforce various policies. It currently supports

Mar 25, 2022
A sweet n' simple pastebin with syntax highlighting and no client-side code!

sweetpaste sweetpaste is a sweet n' simple pastebin server. It's completely server-side, with zero client-side code. Configuration The configuration w

Jun 17, 2022