Compile time constants and global variables

I’m trying to convert a Nim program to Rust. I’m able to write and test each proc/functions/routine separately and verify they work (create correct output).

The problem I’m having is creating the whole program where I’m using global variables and am creating at compile time some runtime constants.

Here’s link the whole Nim code:

The particular problem is trying to do the compile time constant compilations, as shown here:

proc genPGparameters(prime: int): (int, int, int, seq[int], seq[int], seq[int]) =
  ## Create constant parameters for given PG at compile time.
  echo("generating parameters for P", prime)
  let primes = [2, 3, 5, 7, 11, 13, 17, 19, 23]
  var modpg = 1
  for prm in primes: (modpg *= prm; if prm == prime: break)  # PG's mdoulus

  var residues: seq[int] = @[]    # generate PG's residue values here
  var (pc, inc) = (5, 2)
  while pc < modpg div 2:
    if gcd(modpg, pc) == 1: residues.add(pc); residues.add(modpg - pc)
    pc += inc; inc = inc xor 0b110
  residues.sort(system.cmp[int]); residues.add(modpg - 1); residues.add(modpg + 1)
  let rescnt = residues.len       # PG's residues count

  var restwins: seq[int] = @[]    # extract upper twinpair residues here
  var j = 0
  while j < rescnt - 1:
    if residues[j] + 2 == residues[j + 1]: restwins.add(residues[j + 1]);
  let twinpairs = restwins.len    # twinpairs count

  var inverses: seq[int] = @[]    # create PG's residues inverses here
  for res in residues: inverses.add(modinv(res, modpg))

  result = (modpg, rescnt, twinpairs, residues, restwins, inverses)

# Generate at compile time the parameters for PGs.
const parametersp5  = genPGparameters(5)
const parametersp7  = genPGparameters(7)
const parametersp11 = genPGparameters(11)
const parametersp13 = genPGparameters(13)
const parametersp17 = genPGparameters(17)

# Global parameters
  pcnt = 0             # number of primes from r1..sqrt(N)
  num = 0'u64          # adjusted (odd) input value
  twinscnt = 0'u64     # number of twin primes <= N
  primes: seq[int]     # list of primes r1..sqrt(N)
  KB = 0               # segment size for each seg restrack
  cnts: seq[uint]      # hold twin primes counts for seg bytes
  lastwins: seq[uint]  # holds largest twin prime <= num in each thread
  pos: seq[int]        # convert residue val to its residues index val
                       # faster than `residues.index(residue)`
  modpg:     int       # PG's modulus value
  rescnt:    int       # PG's residues count
  pairscnt:  int       # PG's twinpairs count
  residues:  seq[int]  # PG's list of residues
  restwins:  seq[int]  # PG's list of twinpair residues
  resinvrs:  seq[int]  # PG's list of residues inverses
  Bn:        int       # segment size factor for PG and input number

I heard Rust doesn’t allow globals, if so what is the equivalent process to achieve what I want?
The ultimate goal is to create the Rust version of this algorithm and benchmark it to the Nim and D versions I have. Someone did an old Rust version of an older (slower) implementation, but now I’m trying to see if I can do a Rust version myself to implement the new version.

I would appreciate any help and suggestions.

Rust does have globals, but it is very hard to use them. I would recommend trying to refactor your code to not use globals.

Here is how you create globals, not that globals are read-only be default, so you will need to use some syncronization like a Mutex to write to them.

static NAME: Type = Value;
1 Like

The lazy_static crate might also be worth to have a look at. I use it in rs-pbrt

In particular (see RADICAL_INVERSE_PERMUTATIONS, a Vec<u16>, which gets initialized by the
compute_radical_inverse_permutations function which gets called only once by lazy_static!):

lazy_static::lazy_static! {
    static ref RADICAL_INVERSE_PERMUTATIONS: Vec<u16> = {
        let mut rng: Rng = Rng::new();
        let radical_inverse_permutations: Vec<u16> = compute_radical_inverse_permutations(&mut rng);