Rust has been on Stack Overflow’s most loved languages list for the last six years. Wow.

What makes the Rust programming language so popular?

C and C++ have always been the golden standard when it comes to speed, but they also came with a price: managing memory (i.e. allocating and deallocating memory) is a nightmare (in general, and in multithreaded applications in particular) for developers.

Quoting Wikipedia:

Rust is a multi-paradigm, high-level, general-purpose programming language designed for performance and safety, especially safe concurrency. Rust is syntactically similar to C++, but can guarantee memory safety by using a borrow checker to validate references. Rust achieves memory safety without garbage collection, and reference counting is optional.

Nuff said. If you are reading this, you probably already know why Rust has gained so much momentum in the last few years. Rust’s strong points are an efficient memory model and a modern build toolchain (Cargo). While its learning curve is steep, it may be the right tool for a variety of tasks, such as console (CLI) and DevOps tools, embedded systems, cryptocurrencies, IOT and, effective September 2021, Device Detection with WURFL.

Starting with version 1.12.2.0, WURFL InFuze introduces a new Rust module that you can use in your applications to look up the capabilities of devices such as smartphones, tablets and desktop web browsers, as well as the long tail of HTTP clients from Smart TVs and up to the wristwatches that some use to surf the web.

This blog post illustrates that specific use-case. We will guide you through building and compiling a command-line application that reads a list of user agent strings from the standard input and writes the device name and some of its properties (WURFL capabilities) to the standard output in TSV format. We provide the code with an open-source license, but of course you will need to acquire a license for the WURFL Module from ScientiaMobile in order to build and run the demo app.

Prerequisites

In order to build the application, you’ll need:

This author was able to install Rust on the Windows Subsystem for Linux in a matter of seconds with:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | shCode language: JavaScript (javascript)

Build the Application

Clone the WURFL Rust example repository:

$ git clone https://github.com/WURFL/infuze-rust-exampleCode language: PHP (php)

then

$ cd infuze-rust/infuze-rust-examples

Open the Cargo.toml  file and replace the actual path of your WURFL InFuze Rust module installation in:

wurfl = { version = "0.9.0", path = "/path-to/rust-wurfl" }.Code language: JavaScript (javascript)

Build the application ($ cargo build). The executable will be created under the directory target/debug.

Execute the application

The application expects user-agent strings to be fed to it through the standard input. The infuze-rust-examples folder contains a file (100_ua.txt) with a list of 100 user-agent strings provided for your convenience.  You can launch the application and pipe those 100 UA strings into our Rust program:

$ cat 100_ua.txt | target/debug/infuze-rust-examples  > outfile.tsv

This will work fine in many Linux distributions, as it assumes a default location of the wurfl.xml/.zip file (/usr/share/wurfl/wurfl.zip). If you execute the application on Windows or Mac OS or other *nix distributions, or if the wurfl.xml file is in a different place, you can specify the location of the WURFL file with the `-w` option. 

$ cat 100_ua.txt | target/debug/infuze-rust-examples -w /path/to/wurfl.zip > outfile.tsv

Look at the Code

First lines are boilerplate code (imports, argument parsing, file path validation, etc.) followed by the instructions that create the WURFL engine:

use std::{env, io};
use std::process::exit;
use wurfl::{Wurfl, WurflCacheProvider};
use std::path::Path;
use std::io::{BufRead, Write};
  
     :
 
let wurfl_res = Wurfl::new(wurfl_path.to_str().unwrap(), None, None,
                          WurflCacheProvider::LRU, Some("100000"));
let engine = match wurfl_res {
   Ok(engine) => engine,
   Err(error) => panic!("Problem initializing wurfl: {:?}", error),
};
Code language: Rust (rust)

Each line of the input contains a user agent string, i.e. the key parameter to the lookup_useragent API call. This returns an instance of the Result<Device, WurflError>  We need to check for a possible error condition before calling unwrap() and get the actual device instance.

We need an instance of the WURFL engine to access all API features. The first parameter is the path to the WURFL file. The two None parameters are used to define an array of WURFL patches and a WURFL capability filter, i.e. two advanced features you probably don’t care about (at least, not yet).

The last parameter configures a LRU cache of 100000 elements. In-memory caching of device lookups enables the (configurable) trade-off between speed and memory. Most users will be fine with the default.

After grabbing the standard input and output handles ( io::stdin() and io::stdout ), we are finally ready to perform device detection on input data:

for line in stdin.lock().lines() {
       let device_res = engine.lookup_useragent(line.unwrap().as_str());
       if device_res.is_err() {
           // skip some unlikely errors
           continue;
       }
       let device = device_res.unwrap();
       let device_name =
device.get_virtual_capability("complete_device_name");
       let is_tablet = device.get_virtual_capability("advertised_device_os");
       let form_factor = device.get_virtual_capability("form_factor");
       let _ = io::stdout().write_all(device_name.unwrap().as_bytes());
       let _ = io::stdout().write_all("\t".as_bytes());
       let _ = io::stdout().write_all(is_tablet.unwrap().as_bytes());
       let _ = io::stdout().write_all("\t".as_bytes());
       let _ = io::stdout().write_all(form_factor.unwrap().as_bytes());
       let _ = io::stdout().write_all("\n".as_bytes());
   }
}

Code language: Rust (rust)

Each line of the input contains a user agent string, i.e. the key parameter to the lookup_useragent API call. This returns an instance of the Result<Device, WurflError>  We need to check for a possible error condition before calling unwrap() and get the actual device instance. 

Once we have our device, we call get_virtual_capability for “complete_device_name”, “advertised_device_os” and “form_factor”. 

Virtual capabilities return properties whose value is based on the evaluation of other static capabilities or further inspection of parameters found in the HTTP request. For more information about virtual and static capabilities, you may want to refer to this page.

Note: for the purposes of this blog post, we are ignoring the return of the write_all call that might be relevant in a real application.

Assuming there are no errors, here’s what output from the demo app looks like.

Device name  OS  Form factor
Samsung SM-T110 (Galaxy Tab 3 Lite) Android Tablet
Opera Mini 4  Feature Phone
itel fp6531  Feature Phone
Xiaomi Mi A1 Android Smartphone
:

We are golden. If Rust is your poison, you can now start thinking of how you can augment your products and services with device intelligence.

Conclusions

Arguably, Rust is one of the most exciting new kids on the block when it comes to programming languages. Companies approached us at the beginning of 2021 and asked if we supported Rust. We didn’t at the time, but we listened!

Rust has occupied a sweet spot that wasn’t quite covered by other programming languages old and new. But, as programmers know, being good at something is only part of the story when it comes to adopting a new language, the other part is access to a rich module library to cover all use cases. Rust missed a device detection module. ScientiaMobile has got you covered: with WURFL InFuze for Rust, accessing device properties is now just as easy as with any other language that we support (all major ones!).

{"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

Want access to the latest mobile device trends?

Download the Mobile Overview Report.

>