| #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); | |
| } | |
| } |