I am just starting out with Rust and NEAR and trying to create a simple function that counts how many NFTs have been minted with a particular substring.
My NFTs have a token_id which contains a randomstring-tier1 or randomstring-tier2 and rather than returning the total amount minted. i want o know for each tier.
I have this very basic function that returns the total count.
pub fn nft_total_supply(&self) -> U128 {
//return the length of the token metadata by ID
U128(self.token_metadata_by_id.len() as u128)
}
But not got a good enough understanding of how I check the token_id for a particular sub-string.
Was trying
pub fn check_nft_minted_by_tier1(
&self,
token_id
) -> u128 {
if token_id.contains("tier1").count() {
U128(tier1.len() as u128)
}
}
But this doesn't work.
My personal recommendation is to have this information stored in state that way you can quickly access it with little computation and it's also scalable. If the list of NFTs grows very high, you might not have enough GAS to loop through each and check the token ID for the substring.
I would store something in state that either keeps track of the number of NFTs with each tier, or keeps track of the token IDs for each tier. That way you can expand later and maybe get the metadata as well rather than just the total number of NFTs.
This set of token IDs can be populated upon minting an NFT. At the end of the mint function, you can add a quick check to see if the token ID contains the sub-string and then add it to the list if it does. You can reference this post to see how you can check for a sub-string.
Related
I've been trying use matchAll in node.js, but when I run the code and log the return value it only shows Object [RegExp String Iterator] {}.
Could you help me to understand why this is the case?
Be mindful of the types of things you are working with.
To quote the docs for String.prototype.matchAll:
The matchAll() method returns an iterator of all results matching a string against a regular expression, including capturing groups.
(Emphasis mine.)
So, you get an iterator. What is an iterator? Well, the docs say:
In JavaScript an iterator is an object which defines a sequence and potentially a return value upon its termination.
[...]
While it is easy to imagine that all iterators could be expressed as arrays, this is not true. Arrays must be allocated in their entirety, but iterators are consumed only as necessary. Because of this, iterators can express sequences of unlimited size, such as the range of integers between 0 and Infinity.
So, matchAll will only do the actual work of finding the next match when you ask for it, by asking for next value of the iterator, and the amount of state that has to be kept won't increase that much with a longer string because not all matches have to be remembered at once. That's the beauty of iterators (and their opposite part, generators).
This is also why you won't see all the results in your console when printing the iterator - otherwise, a matchAll on a very very large string would cause a long delay and high CPU usage when its return value is merely logged to the console, which wouldn't make sense.
You can use the result of matchAll in a for of loop, which will look for the next match every time the loop repeats:
for (const match of 'abcde'.matchAll(/./g)) {
console.log(match)
}
// Prints 5 times something like ['a', index: 0, input: 'abcde', groups: undefined ]
Or, if you are willing to forgo the benefit of on-demand matching, you can extract all values from the iterator at once and fit them into an array using either spread syntax or Array.from:
const allMatches = [...'abcde'.matchAll(/./g)]
// - or -
const allMatches = Array.from('abcde'.matchAll(/./g))
(In fact, the spread syntax is shown in the example at the very top of the matchAll docs too.)
I'm trying out Rust and I really like it so far. I'm working on a tool that needs to get arrow key input from the user. So far, I've got something half-working: if I hold a key for a while, the relevant function gets called. However, it's far from instantaneous.
What I've got so far:
let mut stdout = io::stdout().into_raw_mode();
let mut stdin = termion::async_stdin();
// let mut stdin = io::stdin();
let mut it = stdin.keys(); //iterator object
loop {
//copied straight from GitLab: https://gitlab.redox-os.org/redox-os/termion/-/issues/168
let b = it.next();
match b {
Some(x) => match x {
Ok(k) => {
match k {
Key::Left => move_cursor(&mut cursor_char, -1, &enc_chars, &mpt, &status),
Key::Right => move_cursor(&mut cursor_char, 1, &enc_chars, &mpt, &status),
Key::Ctrl('c') => break,
_ => {}
}
},
_ => {}
},
None => {}
}
//this loop might do nothing if no recognized key was pressed.
}
I don't quite understand it myself. I'm using the terminal raw mode, if that has anything to do with it. I've looked at the rustyline crate, but that's really no good as it's more of an interactive shell-thing, and I just want to detect keypresses.
If you're using raw input mode and reading key by key, you'll need to manually buffer the character keys using the same kind of match loop you already have. The Key::Char(ch) enum variant can be used to match regular characters. You can then use either a mutable String or an array like [u8; MAX_SIZE] to store the character data and append characters as they're typed. If the user moves the cursor, you'd need to keep track of the current position within your input buffer and make sure to insert the newly typed characters into the correct spot, moving the existing characters if needed. It is a lot of work, which is why there are crates that will do it for you, but you will have less chance to control how the input behaves. If you want to use an existing crate, then tui-rs might be a good one to check out for a complete solution, or linefeed for something much simpler.
As for the delay, I think it might be because you're using AsyncReader, which according to the docs is using a secondary thread to do blocking reads
I'm querying for existing records in a table called messages; this query is then used as part of a 'find or create' function:
fn find_msg_by_uuid<'a>(conn: &PgConnection, msg_uuid: &Uuid) -> Option<Vec<Message>> {
use schema::messages::dsl::*;
use diesel::OptionalExtension;
messages.filter(uuid.eq(msg_uuid))
.limit(1)
.load::<Message>(conn)
.optional().unwrap()
}
I've made this optional as both finding a record and finding none are both valid outcomes in this scenario, so as a result this query might return a Vec with one Message or an empty Vec, so I always end up checking if the Vec is empty or not using code like this:
let extant_messages = find_msg_by_uuid(conn, message_uuid);
if !extant_messages.unwrap().is_empty() { ... }
and then if it isnt empty taking the first Message in the Vec as my found message using code like
let found_message = find_msg_by_uuid(conn, message_uuid).unwrap()[0];
I always take the first element in the Vec since the records are unique so the query will only ever return 1 or 0 records.
This feels kind of messy to me and seems to take too many steps, I feel as if there is a record for the query then it should return Option<Message> not Option<Vec<Message>> or None if there is no record matching the query.
As mentioned in the comments, use first:
Attempts to load a single record. Returns Ok(record) if found, and Err(NotFound) if no results are returned. If the query truly is optional, you can call .optional() on the result of this to get a Result<Option<U>>.
fn find_msg_by_uuid<'a>(conn: &PgConnection, msg_uuid: &Uuid) -> Option<Message> {
use schema::messages::dsl::*;
use diesel::OptionalExtension;
messages
.filter(uuid.eq(msg_uuid))
.first(conn)
.optional()
.unwrap()
}
I am trying to understand the implementation of linux kernel's hash table. What I don't understand is that I find code initializing a hash table with only a single hash bucket. I don't know why the coding is doing that.
This hash table usage makes sense to me:
In kernel/pid.c:
void __init pidhash_init(void)
{
unsigned int i, pidhash_size;
pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18,
HASH_EARLY | HASH_SMALL,
&pidhash_shift, NULL,
0, 4096);
pidhash_size = 1U << pidhash_shift;
for (i = 0; i < pidhash_size; i++)
INIT_HLIST_HEAD(&pid_hash[i]);
}
pid_hash is a list of struct hlist_head, so each entry in the list represents a hash bucket.
However this usage doesn't make sense to me:
In drivers/android/binder.c of goldfish branch:
static HLIST_HEAD(binder_dead_nodes);
It expands to
struct hlist_head name = { .first = NULL }
Basically it is a hash table with only one hlist_head, namely a hash table with only one hash bucket. So it is actually a double linked list. Why people wants to create a hash table with a single hash bucket like this?
hlist is just a regular double linked list.
The difference between list and hlist is just that hlist trades O(1) access to the tail of the list for a 50% memory reduction for empty lists. This is perfect for hash tables, which have lots of empty lists and never need to access a list in reverse or from behind.
However, it's also great for regular linked lists.
By using hlist they saved a few bytes over list, and gave us a strong signal that the list is used to collect an unknown number of items in an order that doesn't matter.
I'm currently trying to implement my own DynamicArray data type in Swift. To do so I'm using pointers a bit. As my root I'm using an UnsafeMutablePointer of a generic type T:
struct DynamicArray<T> {
private var root: UnsafeMutablePointer<T> = nil
private var capacity = 0 {
didSet {
//...
}
}
//...
init(capacity: Int) {
root = UnsafeMutablePointer<T>.alloc(capacity)
self.capacity = capacity
}
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
for index in 0..<count {
(root + index).memory = repeatedValue
}
self.count = count
}
//...
}
Now as you can see I've also implemented a capacity property which tells me how much memory is currently allocated for root. Accordingly one can create an instance of DynamicArray using the init(capacity:) initializer, which allocates the appropriate amount of memory, and sets the capacity property.
But then I also implemented the init(count:repeatedValue:) initializer, which first allocates the needed memory using init(capacity: count). It then sets each segment in that part of memory to the repeatedValue.
When using the init(count:repeatedValue:) initializer with number types like Int, Double, or Float it works perfectly fine. Then using Character, or String though it crashes. It doesn't crash consistently though, but actually works sometimes, as can be seen here, by compiling a few times.
var a = DynamicArray<Character>(count: 5, repeatedValue: "A")
println(a.description) //prints [A, A, A, A, A]
//crashes most of the time
var b = DynamicArray<Int>(count: 5, repeatedValue: 1)
println(a.description) //prints [1, 1, 1, 1, 1]
//works consistently
Why is this happening? Does it have to do with String and Character holding values of different length?
Update #1:
Now #AirspeedVelocity addressed the problem with init(count:repeatedValue:). The DynamicArray contains another initializer though, which at first worked in a similar fashion as init(count:repeatedValue:). I changed it to work, as #AirspeedVelocity described for init(count:repeatedValue:) though:
init<C: CollectionType where C.Generator.Element == T, C.Index.Distance == Int>(collection: C) {
let collectionCount = countElements(collection)
self.init(capacity: collectionCount)
root.initializeFrom(collection)
count = collectionCount
}
I'm using the initializeFrom(source:) method as described here. And since collection conforms to CollectionType it should work fine.
I'm now getting this error though:
<stdin>:144:29: error: missing argument for parameter 'count' in call
root.initializeFrom(collection)
^
Is this just a misleading error message again?
Yes, chances are this doesn’t crash with basic inert types like integers but does with strings or arrays because they are more complex and allocate memory for themselves on creation/destruction.
The reason it’s crashing is that UnsafeMutablePointer memory needs to be initialized before it’s used (and similarly, needs to de-inited with destroy before it is deallocated).
So instead of assigning to the memory property, you should use the initialize method:
for index in 0..<count {
(root + index).initialize(repeatedValue)
}
Since initializing from another collection of values is so common, there’s another version of initialize that takes one. You could use that in conjunction with another helper struct, Repeat, that is a collection of the same value repeated multiple times:
init(count: Int, repeatedValue: T) {
self.init(capacity: count)
root.initializeFrom(Repeat(count: count, repeatedValue: repeatedValue))
self.count = count
}
However, there’s something else you need to be aware of which is that this code is currently inevitably going to leak memory. The reason being, you will need to destroy the contents and dealloc the pointed-to memory at some point before your DynamicArray struct is destroyed, otherwise you’ll leak. Since you can’t have a deinit in a struct, only a class, this won’t be possible to do automatically (this is assuming you aren’t expecting users of your array to do this themselves manually before it goes out of scope).
Additionally, if you want to implement value semantics (as with Array and String) via copy-on-write, you’ll also need a way of detecting if your internal buffer is being referenced multiple times. Take a look at ManagedBufferPointer to see a class that handles this for you.