#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
#include <stdint.h> | |
#include <stdlib.h> | |
struct expanded_key { | |
uint32_t l[16], r[16]; | |
}; | |
void __des_setkey(const unsigned char *key, struct expanded_key *ekey); | |
void __do_des(uint32_t l_in, uint32_t r_in, | |
uint32_t *l_out, uint32_t *r_out, | |
uint32_t count, uint32_t saltbits, const struct expanded_key *ekey); | |
static struct expanded_key __encrypt_key; | |
void setkey(const char *key) | |
{ | |
unsigned char bkey[8]; | |
int i, j; | |
for (i = 0; i < 8; i++) { | |
bkey[i] = 0; | |
for (j = 7; j >= 0; j--, key++) | |
bkey[i] |= (uint32_t)(*key & 1) << j; | |
} | |
__des_setkey(bkey, &__encrypt_key); | |
} | |
void encrypt(char *block, int edflag) | |
{ | |
struct expanded_key decrypt_key, *key; | |
uint32_t b[2]; | |
int i, j; | |
char *p; | |
p = block; | |
for (i = 0; i < 2; i++) { | |
b[i] = 0; | |
for (j = 31; j >= 0; j--, p++) | |
b[i] |= (uint32_t)(*p & 1) << j; | |
} | |
key = &__encrypt_key; | |
if (edflag) { | |
key = &decrypt_key; | |
for (i = 0; i < 16; i++) { | |
decrypt_key.l[i] = __encrypt_key.l[15-i]; | |
decrypt_key.r[i] = __encrypt_key.r[15-i]; | |
} | |
} | |
__do_des(b[0], b[1], b, b + 1, 1, 0, key); | |
p = block; | |
for (i = 0; i < 2; i++) | |
for (j = 31; j >= 0; j--) | |
*p++ = b[i]>>j & 1; | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
// Copyright 2016 The Go Authors. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package http | |
import ( | |
"io" | |
"strconv" | |
"strings" | |
"time" | |
"unicode/utf8" | |
"golang_org/x/net/lex/httplex" | |
) | |
// maxInt64 is the effective "infinite" value for the Server and | |
// Transport's byte-limiting readers. | |
const maxInt64 = 1<<63 - 1 | |
// aLongTimeAgo is a non-zero time, far in the past, used for | |
// immediate cancelation of network operations. | |
var aLongTimeAgo = time.Unix(1, 0) | |
// TODO(bradfitz): move common stuff here. The other files have accumulated | |
// generic http stuff in random places. | |
// contextKey is a value for use with context.WithValue. It's used as | |
// a pointer so it fits in an interface{} without allocation. | |
type contextKey struct { | |
name string | |
} | |
func (k *contextKey) String() string { return "net/http context value " + k.name } | |
// Given a string of the form "host", "host:port", or "[ipv6::address]:port", | |
// return true if the string includes a port. | |
func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } | |
// removeEmptyPort strips the empty port in ":port" to "" | |
// as mandated by RFC 3986 Section 6.2.3. | |
func removeEmptyPort(host string) string { | |
if hasPort(host) { | |
return strings.TrimSuffix(host, ":") | |
} | |
return host | |
} | |
func isNotToken(r rune) bool { | |
return !httplex.IsTokenRune(r) | |
} | |
func isASCII(s string) bool { | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
return false | |
} | |
} | |
return true | |
} | |
func hexEscapeNonASCII(s string) string { | |
newLen := 0 | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
newLen += 3 | |
} else { | |
newLen++ | |
} | |
} | |
if newLen == len(s) { | |
return s | |
} | |
b := make([]byte, 0, newLen) | |
for i := 0; i < len(s); i++ { | |
if s[i] >= utf8.RuneSelf { | |
b = append(b, '%') | |
b = strconv.AppendInt(b, int64(s[i]), 16) | |
} else { | |
b = append(b, s[i]) | |
} | |
} | |
return string(b) | |
} | |
// NoBody is an io.ReadCloser with no bytes. Read always returns EOF | |
// and Close always returns nil. It can be used in an outgoing client | |
// request to explicitly signal that a request has zero bytes. | |
// An alternative, however, is to simply set Request.Body to nil. | |
var NoBody = noBody{} | |
type noBody struct{} | |
func (noBody) Read([]byte) (int, error) { return 0, io.EOF } | |
func (noBody) Close() error { return nil } | |
func (noBody) WriteTo(io.Writer) (int64, error) { return 0, nil } | |
var ( | |
// verify that an io.Copy from NoBody won't require a buffer: | |
_ io.WriterTo = NoBody | |
_ io.ReadCloser = NoBody | |
) | |
// PushOptions describes options for Pusher.Push. | |
type PushOptions struct { | |
// Method specifies the HTTP method for the promised request. | |
// If set, it must be "GET" or "HEAD". Empty means "GET". | |
Method string | |
// Header specifies additional promised request headers. This cannot | |
// include HTTP/2 pseudo header fields like ":path" and ":scheme", | |
// which will be added automatically. | |
Header Header | |
} | |
// Pusher is the interface implemented by ResponseWriters that support | |
// HTTP/2 server push. For more background, see | |
// https://tools.ietf.org/html/rfc7540#section-8.2. | |
type Pusher interface { | |
// Push initiates an HTTP/2 server push. This constructs a synthetic | |
// request using the given target and options, serializes that request | |
// into a PUSH_PROMISE frame, then dispatches that request using the | |
// server's request handler. If opts is nil, default options are used. | |
// | |
// The target must either be an absolute path (like "/path") or an absolute | |
// URL that contains a valid host and the same scheme as the parent request. | |
// If the target is a path, it will inherit the scheme and host of the | |
// parent request. | |
// | |
// The HTTP/2 spec disallows recursive pushes and cross-authority pushes. | |
// Push may or may not detect these invalid pushes; however, invalid | |
// pushes will be detected and canceled by conforming clients. | |
// | |
// Handlers that wish to push URL X should call Push before sending any | |
// data that may trigger a request for URL X. This avoids a race where the | |
// client issues requests for X before receiving the PUSH_PROMISE for X. | |
// | |
// Push returns ErrNotSupported if the client has disabled push or if push | |
// is not supported on the underlying connection. | |
Push(target string, opts *PushOptions) error | |
} |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<title>paint demo</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" type="text/css" media="screen" href="main.css" /> | |
<link rel="stylesheet" type="text/css" media="screen" href="snippets.css" /> | |
</head> | |
<body> | |
<div class="container"> | |
<div class="command"> | |
<h1> | |
<span class="hue-rotate">$</span> paint | |
./file.<span id="ext">rs</span> | |
<nobr>--style="<span id="style-name">github</span>"</nobr> | |
<nobr>--gist-like</nobr> | |
<nobr><span id="lines"></span></nobr> | |
</h1> | |
</div> | |
<div class="flex-centered"> | |
<select id="filetype"> | |
<option selected value="rs">rust</option> | |
<option value="js">javascript</option> | |
<option value="jsx">jsx</option> | |
<option value="html">html</option> | |
<option value="c">c</option> | |
<option value="py">python</option> | |
<option value="go">go</option> | |
</select> | |
<select id="style"> | |
<option value="atom_dark">atom dark</option> | |
<option value="ayu_dark">ayu dark</option> | |
<option value="ayu_light">ayu light</option> | |
<option value="ayu_mirage">ayu mirage</option> | |
<option value="cobalt2">cobalt2</option> | |
<option value="dracula">dracula</option> | |
<option selected value="github">github</option> | |
<option value="monokai_extended">monokai extended</option> | |
<option value="oceanic_next">oceanic next</option> | |
<option value="one_dark">one dark</option> | |
<option value="one_light">one light</option> | |
<option value="one_monokai">one monokai</option> | |
<option value="predawn">predawn</option> | |
<option value="solarized_dark">solarized dark</option> | |
<option value="solarized_light">solarized light</option> | |
<option value="wombat">wombat</option> | |
</select> | |
<input id="highlight" type="checkbox" /> | |
<label for="highlight"><nobr>--highlight</nobr></label> | |
</div> | |
<div id="highlighted" class="no-hi" data-style="github--rs" data-filetype="rs"> | |
</div> <!-- highlighted --> | |
<div class="gh"> | |
<a href="https://github.com/demille/paint"> | |
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> | |
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/> | |
</svg> | |
<span>/demille/paint</span> | |
</a> | |
</div> | |
</div> <!-- container --> | |
<div class="bg-overlay"></div> | |
<script src="main.js"></script> | |
</body> | |
</html> |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import Struct from './Struct'; | |
import { types, parseType, Pointer } from './types'; | |
import { assert, vslice } from './misc'; | |
const DATA = (typeof Symbol !== 'undefined') | |
? Symbol.for('struct-data') | |
: '__data'; | |
function extend(StructType) { | |
class RustType extends StructType { | |
free() { | |
super.free(true); | |
} | |
} | |
Object.assign(RustType, StructType); | |
return RustType; | |
} | |
function RustTuple(...tupleTypes) { | |
const fields = {}; | |
tupleTypes.forEach((type, i) => { | |
fields[i] = parseType(type); | |
}); | |
return new Struct(fields); | |
} | |
function RustVector(typedef) { | |
const type = parseType(typedef); | |
const Vector = extend(new Struct({ | |
ptr: types.pointer(type), | |
cap: 'usize', | |
len: 'usize', | |
/* values */ | |
})); | |
Object.defineProperty(Vector.prototype, 'values', { | |
enumerable: true, | |
get() { | |
const arrayType = parseType([type, this.len]); | |
const memory = this[DATA].view.buffer; | |
const view = new DataView(memory, this.ptr.ref(), arrayType.width); | |
return arrayType.read(view, this[DATA].free); | |
}, | |
set(values) { | |
const len = values.length; | |
this.ptr = new Pointer([type, len], values); | |
this.len = len; | |
this.cap = len; | |
}, | |
}); | |
return Vector; | |
} | |
function RustOption(typedef, isNonNullable = false, tagSize) { | |
const type = parseType(typedef); | |
let discriminant; | |
if (tagSize) discriminant = types[`uint${tagSize * 8}`]; | |
else if (type.alignment === 1) discriminant = 'uint8'; | |
else if (type.alignment === 2) discriminant = 'uint16'; | |
else discriminant = 'uint32'; | |
const fields = (isNonNullable) | |
? { value: type } | |
: { discriminant, value: type }; | |
const Option = new Struct(fields); | |
Object.assign(Option.prototype, { | |
isSome() { | |
return ('discriminant' in fields) ? !!this.discriminant : !!this.value; | |
}, | |
isNone() { | |
return !this.isSome(); | |
}, | |
expect(msg) { | |
if (!this.isSome()) throw new Error(msg); | |
return this.value; | |
}, | |
unwrap() { | |
if (!this.isSome()) throw new Error('Error unwrapping none'); | |
return this.value; | |
}, | |
unwrapOr(defaultValue) { | |
return (this.isSome()) ? this.value : defaultValue; | |
}, | |
unwrapOrElse(fn) { | |
return (this.isSome()) ? this.value : fn(); | |
}, | |
}); | |
return Option; | |
} | |
const rust = { | |
tuple: RustTuple, | |
Tuple: (type, values) => new (RustTuple(...type))([...values]), | |
vector: RustVector, | |
Vector: (type, values) => new (RustVector(type))({ values }), | |
option: RustOption, | |
Option: (type, value, ...opts) => new (RustOption(type, ...opts))({ | |
value, | |
discriminant: (typeof value === 'undefined') ? 0 : 1, | |
}), | |
Some: (...args) => rust.Option(...args), | |
None: (type, ...opts) => rust.Option(type, undefined, ...opts), | |
}; | |
export default rust; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
import React from 'react'; | |
import Display from './Display'; | |
import ButtonPanel from './ButtonPanel'; | |
import calculate from '../logic/calculate'; | |
import './App.css'; | |
class App extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
total: null, | |
next: null, | |
operation: null, | |
}; | |
} | |
handleClick = (buttonName) => { | |
this.setState(calculate(this.state, buttonName)); | |
} | |
render() { | |
return ( | |
<div className="component-app"> | |
<Display | |
value={this.state.next || this.state.total || '0'} | |
/> | |
<ButtonPanel | |
clickHandler={this.handleClick} | |
/> | |
</div> | |
); | |
} | |
} | |
export default App; |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
from django.utils.cache import ( | |
cc_delim_re, get_conditional_response, set_response_etag, | |
) | |
from django.utils.deprecation import MiddlewareMixin | |
from django.utils.http import parse_http_date_safe | |
class ConditionalGetMiddleware(MiddlewareMixin): | |
""" | |
Handle conditional GET operations. If the response has an ETag or | |
Last-Modified header and the request has If-None-Match or If-Modified-Since, | |
replace the response with HttpNotModified. Add an ETag header if needed. | |
""" | |
def process_response(self, request, response): | |
# It's too late to prevent an unsafe request with a 412 response, and | |
# for a HEAD request, the response body is always empty so computing | |
# an accurate ETag isn't possible. | |
if request.method != 'GET': | |
return response | |
if self.needs_etag(response) and not response.has_header('ETag'): | |
set_response_etag(response) | |
etag = response.get('ETag') | |
last_modified = response.get('Last-Modified') | |
last_modified = last_modified and parse_http_date_safe(last_modified) | |
if etag or last_modified: | |
return get_conditional_response( | |
request, | |
etag=etag, | |
last_modified=last_modified, | |
response=response, | |
) | |
return response | |
def needs_etag(self, response): | |
"""Return True if an ETag header should be added to response.""" | |
cache_control_headers = cc_delim_re.split(response.get('Cache-Control', '')) | |
return all(header.lower() != 'no-store' for header in cache_control_headers) |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |
use std::collections::{BTreeMap, HashMap}; | |
use std::hash::Hash; | |
use onig::{Regex, RegexOptions, Region, Syntax}; | |
use std::rc::{Rc, Weak}; | |
use std::cell::RefCell; | |
use super::scope::*; | |
use regex_syntax::escape; | |
use serde::{Deserialize, Deserializer, Serialize, Serializer}; | |
/// The main data structure representing a syntax definition loaded from a | |
/// `.sublime-syntax` file. You'll probably only need these as references | |
/// to be passed around to parsing code. | |
/// | |
/// Some useful public fields are the `name` field which is a human readable | |
/// name to display in syntax lists, and the `hidden` field which means hide | |
/// this syntax from any lists because it is for internal use. | |
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] | |
pub struct SyntaxDefinition { | |
pub name: String, | |
pub file_extensions: Vec<String>, | |
pub scope: Scope, | |
pub first_line_match: Option<String>, | |
pub hidden: bool, | |
/// Filled in at link time to avoid serializing it multiple times | |
#[serde(skip_serializing, skip_deserializing)] | |
pub prototype: Option<ContextPtr>, | |
#[serde(serialize_with = "ordered_map")] | |
pub variables: HashMap<String, String>, | |
#[serde(serialize_with = "ordered_map")] | |
pub contexts: HashMap<String, ContextPtr>, | |
} | |
impl Context { | |
/// Returns the match pattern at an index, panics if the thing isn't a match pattern | |
pub fn match_at(&self, index: usize) -> &MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
/// Returns a mutable reference, otherwise like `match_at` | |
pub fn match_at_mut(&mut self, index: usize) -> &mut MatchPattern { | |
match self.patterns[index] { | |
Pattern::Match(ref mut match_pat) => match_pat, | |
_ => panic!("bad index to match_at"), | |
} | |
} | |
} | |
impl ContextReference { | |
/// find the pointed to context, panics if ref is not linked | |
pub fn resolve(&self) -> ContextPtr { | |
match *self { | |
ContextReference::Inline(ref ptr) => ptr.clone(), | |
ContextReference::Direct(ref ptr) => ptr.link.upgrade().unwrap(), | |
_ => panic!("Can only call resolve on linked references: {:?}", self), | |
} | |
} | |
} | |
impl MatchPattern { | |
/// substitutes back-refs in Regex with regions from s | |
/// used for match patterns which refer to captures from the pattern | |
/// that pushed them. | |
pub fn regex_with_substitutes(&self, region: &Region, s: &str) -> String { | |
let mut reg_str = String::new(); | |
let mut last_was_escape = false; | |
for c in self.regex_str.chars() { | |
if last_was_escape && c.is_digit(10) { | |
let val = c.to_digit(10).unwrap(); | |
if let Some((start, end)) = region.pos(val as usize) { | |
let escaped = escape(&s[start..end]); | |
reg_str.push_str(&escaped); | |
} | |
} else if last_was_escape { | |
reg_str.push('\\'); | |
reg_str.push(c); | |
} else if c != '\\' { | |
reg_str.push(c); | |
} | |
last_was_escape = c == '\\' && !last_was_escape; | |
} | |
reg_str | |
} | |
/// Makes sure the regex is compiled if it doesn't have captures. | |
/// May compile the regex if it isn't, panicing if compilation fails. | |
#[inline] | |
pub fn ensure_compiled_if_possible(&mut self) { | |
if self.regex.is_none() && !self.has_captures { | |
self.compile_regex(); | |
} | |
} | |
} | |
/// This wrapper only exists so that I can implement a serialization | |
/// trait that crashes if you try and serialize this. | |
#[derive(Debug)] | |
pub struct LinkerLink { | |
pub link: Weak<RefCell<Context>>, | |
} | |
impl Eq for LinkerLink {} | |
impl PartialEq for LinkerLink { | |
fn eq(&self, other: &LinkerLink) -> bool { | |
self.link.upgrade() == other.link.upgrade() | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl Serialize for LinkerLink { | |
fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error> where S: Serializer { | |
panic!("Can't serialize syntax definitions which have been linked"); | |
} | |
} | |
/// Just panics, we can't do anything with linked up syntaxes | |
impl<'de> Deserialize<'de> for LinkerLink { | |
fn deserialize<D>(_: D) -> Result<Self, D::Error> where D: Deserializer<'de> { | |
panic!("No linked syntax should ever have gotten serialized"); | |
} | |
} | |
/// Serialize the provided map in natural key order, so that it's deterministic when dumping. | |
fn ordered_map<K, V, S>(map: &HashMap<K, V>, serializer: S) -> Result<S::Ok, S::Error> | |
where S: Serializer, K: Eq + Hash + Ord + Serialize, V: Serialize | |
{ | |
let ordered: BTreeMap<_, _> = map.iter().collect(); | |
ordered.serialize(serializer) | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::*; | |
#[test] | |
fn can_compile_refs() { | |
use onig::{SearchOptions, Regex, Region}; | |
let pat = MatchPattern { | |
has_captures: true, | |
regex_str: String::from(r"lol \\ \2 \1 '\9' \wz"), | |
regex: None, | |
scope: vec![], | |
captures: None, | |
operation: MatchOperation::None, | |
with_prototype: None, | |
}; | |
let r = Regex::new(r"(\\\[\]\(\))(b)(c)(d)(e)").unwrap(); | |
let mut region = Region::new(); | |
let s = r"\[]()bcde"; | |
assert!(r.match_with_options(s, 0, SearchOptions::SEARCH_OPTION_NONE, Some(&mut region)).is_some()); | |
let regex_res = pat.regex_with_substitutes(®ion, s); | |
assert_eq!(regex_res, r"lol \\ b \\\[\]\(\) '' \wz"); | |
pat.compile_with_refs(®ion, s); | |
} | |
} |